Testing & Simulation
v1.0.0Complete testing guide for SystemOne workflows in Laravel applications using Pest, PHPUnit, and HTTP mocking.
Testing & Simulation
One of the biggest pain points of AI in production applications is flaky, expensive tests. Traditional LLM tests often hit live endpoints, racking up API bills and introducing non-deterministic race conditions.
Obelaw SystemOne is designed for 100% deterministic, offline testing with zero token costs and sub-millisecond execution times.
flowchart TD
subgraph TestingStrategies["SystemOne Deterministic Testing Matrix"]
direction TB
S1["Strategy 1: Http::fake()<br/>Simulate Cloudflare Workers AI responses<br/><b>Best for:</b> Integration & Feature tests"]
S2["Strategy 2: In-Memory Mock Driver<br/>SystemOne::extend('test_driver')<br/><b>Best for:</b> Fast unit tests & service layer isolation"]
S3["Strategy 3: Payload Schema Assertions<br/>Verify $request->toPayload() serialization<br/><b>Best for:</b> Dynamic primitive generation tests"]
end
Outcome["100% Deterministic • Zero API Token Costs • Sub-millisecond Execution"]
TestingStrategies --> Outcome
Strategy 1: Faking Cloudflare HTTP Responses
Because obelaw/systemone-clef uses Laravel’s native Illuminate\Support\Facades\Http client, you can use Http::fake() to simulate any Cloudflare Workers AI response.
sequenceDiagram
autonumber
participant Test as Test Runner (Pest / PHPUnit)
participant HttpFake as Laravel Http::fake()
participant Service as Business Service
participant Engine as SystemOne Clef Driver
Test->>HttpFake: Define mock response for Workers AI endpoint
Test->>Service: invoke analyzeOrder()
Service->>Engine: SystemOne::state(...)->ask(...)->run()
Engine->>HttpFake: POST to api.cloudflare.com/client/v4/...
HttpFake-->>Engine: Mocked JSON { answers: { is_fraud: 0.985, ... } }
Engine-->>Service: DecisionResponse instance
Service-->>Test: Processed order status
Test->>Test: expect($response->value('is_fraud'))->toBe(0.985)
Test->>HttpFake: Http::assertSent(...) verifies request payload
Pest Example
use Illuminate\Support\Facades\Http;
use Obelaw\SystemOne\Facades\SystemOne;
use Obelaw\SystemOne\Primitives\Choice;
use Obelaw\SystemOne\Primitives\Noul;
it('evaluates fraud and routes payment without making live API calls', function () {
// 1. Fake the Cloudflare Workers AI endpoint
Http::fake([
'https://api.cloudflare.com/client/v4/accounts/*/ai/run/*' => Http::response([
'result' => [
'answers' => [
'is_fraud' => [
'value' => 0.985,
'confidence' => 0.985,
],
'action' => [
'value' => 'block',
'confidence' => 0.96,
'probabilities' => [
'allow' => 0.01,
'challenge' => 0.03,
'block' => 0.96,
],
],
],
],
'success' => true,
'errors' => [],
'messages' => [],
], 200),
]);
// 2. Execute decision request
$response = SystemOne::state('High velocity transactions from VPN IP')
->ask('is_fraud', Noul::make('Is transaction fraudulent?'))
->ask('action', Choice::make('Action', ['allow', 'challenge', 'block']))
->run();
// 3. Assert decision outcomes
expect($response->value('is_fraud'))->toBe(0.985)
->and($response->isPositive('is_fraud', 0.90))->toBeTrue()
->and($response->value('action'))->toBe('block')
->and($response->confidence('action'))->toBe(0.96);
// 4. Assert that the request sent correct payload structure
Http::assertSent(function ($request) {
$data = $request->data();
return $data['model'] === 'clef'
&& $data['state'] === 'High velocity transactions from VPN IP'
&& isset($data['questions']['is_fraud'])
&& isset($data['questions']['action']);
});
});
Strategy 2: In-Memory Mock Drivers
If you are unit testing application service layers and want to avoid HTTP mocking entirely, inject a test driver via SystemOne::extend():
flowchart LR
UnitTest["Unit Test Suite"] --> Extend["SystemOne::extend('test_driver')<br/>Register anonymous DriverInterface class"]
Extend --> InMem["In-Memory Driver Execution<br/>Instantly returns predefined DecisionResponse"]
InMem --> Service["DiscountRecommendationService<br/>Evaluates business rules"]
Service --> Assert["expect($cart->applied_coupon)->toBe('VIP20')<br/>(0ms, Zero Network, Zero Token Cost)"]
use Obelaw\SystemOne\Contracts\DecisionResponseInterface;
use Obelaw\SystemOne\Contracts\DriverInterface;
use Obelaw\SystemOne\DecisionRequest;
use Obelaw\SystemOne\DecisionResponse;
use Obelaw\SystemOne\Facades\SystemOne;
beforeEach(function () {
SystemOne::extend('test_driver', function () {
return new class implements DriverInterface {
public function decide(DecisionRequest $request): DecisionResponseInterface
{
return new DecisionResponse([
'is_eligible' => ['value' => 1.0, 'confidence' => 1.0],
'discount_tier' => ['value' => 'vip_20', 'confidence' => 0.95],
]);
}
public function run(DecisionRequest $request): DecisionResponseInterface
{
return $this->decide($request);
}
};
});
});
it('applies VIP discount when decision indicates eligibility', function () {
$cart = createCartWithTotal(500);
$service = new DiscountRecommendationService();
$service->evaluate($cart, driver: 'test_driver');
expect($cart->applied_coupon)->toBe('VIP20');
});
Strategy 3: Unit Testing Primitives Serialization
You can verify that your dynamic schemas are constructed properly before execution:
use Obelaw\SystemOne\Primitives\Choice;
use Obelaw\SystemOne\Primitives\Score;
use Obelaw\SystemOne\DecisionRequest;
it('correctly constructs complex decision payloads', function () {
$request = (new DecisionRequest())
->state(['order_id' => 101])
->ask('category', Choice::make('Select category', [
'books' => 'Physical or digital books',
'electronics' => 'Hardware and gadgets',
]))
->ask('rating', Score::range('Quality score', 1, 5));
$payload = $request->toPayload();
expect($payload['questions']['category']['criteria'])->toHaveKeys(['books', 'electronics'])
->and($payload['questions']['rating']['min'])->toBe(1)
->and($payload['questions']['rating']['max'])->toBe(5);
});
Full Workflow Feature Test Example
Testing a complete business service from end to end:
namespace Tests\Feature;
use App\Models\Order;
use App\Services\OrderRiskService;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;
class OrderRiskFeatureTest extends TestCase
{
public function test_flagged_order_is_marked_for_manual_verification()
{
Http::fake([
'https://api.cloudflare.com/client/v4/accounts/*/ai/run/*' => Http::response([
'result' => [
'answers' => [
'flag_review' => ['value' => 0.92, 'confidence' => 0.92],
],
],
'success' => true,
]),
]);
$order = Order::factory()->create([
'total' => 9999.00,
'is_reviewed' => false,
]);
app(OrderRiskService::class)->analyze($order);
$this->assertTrue($order->fresh()->requires_manual_review);
$this->assertEquals(0.92, $order->fresh()->risk_probability);
}
}
Next Steps
- Explore the complete Overview & Architecture.
- Review all Decision Primitives.