Skip to content

Testing with FakeDriver

Scribe ships with FakeDriver — an in-memory driver that returns whatever you tell it to, with no HTTP calls. Use it whenever you want to test prompt logic, service wiring, or response handling without hitting a real API.

Basic usage

Construct an AIService directly with FakeDriver factories instead of using service('scribe'):

<?php

use Myth\Scribe\AIService;
use Myth\Scribe\Config\AI;
use Myth\Scribe\Drivers\FakeDriver;

// In your test setUp or test method:
$config  = new AI();
$service = new AIService($config, [
    'claude' => static fn () => new FakeDriver(),
]);

$response = $service->run(new MyPrompt());

$this->assertSame('fake-response', $response->content);

FakeDriver returns a response with content = 'fake-response' and model = 'fake-model' by default.

Returning custom responses

Pass an AIResponse into FakeDriver's constructor to control exactly what comes back:

<?php

use Myth\Scribe\AIResponse;
use Myth\Scribe\Drivers\FakeDriver;

$canned = new AIResponse(
    content: '{"label":"SPAM","confidence":0.97}',
    model: 'claude-haiku-4-5',
    inputTokens: 42,
    outputTokens: 18,
    raw: [],
);

$service = new AIService($config, [
    'claude' => static fn () => new FakeDriver($canned),
]);

$response = $service->run(new ClassifyEmailPrompt($emailBody));
$data = $response->toArray();

$this->assertSame('SPAM', $data['label']);
$this->assertSame(0.97, $data['confidence']);

This lets you test the full round-trip — including toArray() decoding and any business logic that acts on the response — without mocking anything.

Testing the toArray() error path

To test that your code handles a non-JSON response gracefully:

<?php

$badResponse = new AIResponse(
    content: 'Sorry, I cannot help with that.',
    model: 'claude-haiku-4-5',
    inputTokens: 10,
    outputTokens: 8,
    raw: [],
);

$service = new AIService($config, [
    'claude' => static fn () => new FakeDriver($badResponse),
]);

$this->expectException(AIException::class);
$service->run(new MyStructuredPrompt())->toArray();

Testing prompt construction

FakeDriver ignores all arguments passed to complete() — which is fine for response-side tests but means you can't assert what the prompt actually sent.

To verify that buildSystemPrompt() produces the right output, test the prompt class directly:

<?php

$prompt = new ClassifyEmailPrompt('Buy cheap meds now!!!');

$this->assertStringContainsString('Classify', $prompt->buildSystemPrompt());
$this->assertSame('Buy cheap meds now!!!', $prompt->userPrompt());
$this->assertNull($prompt->assistant());

Prompt classes are plain PHP — no service container needed. Test them directly.

Testing unknown driver errors

Verify that your code handles an unregistered driver key gracefully:

<?php

$config = new AI();
$config->defaultDriver = 'nonexistent';

$service = new AIService($config, []); // no factories registered

$this->expectException(AIException::class);
$service->run(new MyPrompt());

CI4 test setup

If you're writing CIUnitTestCase tests, extend the base class as usual — the CI4 test bootstrap (set in phpunit.xml.dist) handles service container setup automatically:

<?php

use CodeIgniter\Test\CIUnitTestCase;
use Myth\Scribe\AIService;
use Myth\Scribe\Config\AI;
use Myth\Scribe\Drivers\FakeDriver;

final class ClassifyEmailTest extends CIUnitTestCase
{
    private AIService $service;

    protected function setUp(): void
    {
        parent::setUp();

        $this->service = new AIService(new AI(), [
            'claude' => static fn () => new FakeDriver(
                new AIResponse('{"label":"HAM"}', 'claude-haiku-4-5', 5, 3, [])
            ),
        ]);
    }

    public function testClassifiesHam(): void
    {
        $response = $this->service->run(new ClassifyEmailPrompt('Hi Alice, see you at 3pm.'));
        $this->assertSame('HAM', $response->toArray()['label']);
    }
}

Next steps

  • Prompts — what to test in your prompt classes
  • AIResponse — the full response API