Skip to content

Testing

Want to make sure your Prism integrations work flawlessly? Let's dive into testing! Prism provides a powerful fake implementation that makes it a breeze to test your AI-powered features.

Basic Test Setup

First, let's look at how to set up basic response faking:

php
use EchoLabs\Prism\Prism;
use EchoLabs\Prism\Enums\Provider;
use EchoLabs\Prism\ValueObjects\Usage;
use EchoLabs\Prism\Enums\FinishReason;
use EchoLabs\Prism\Providers\ProviderResponse;

it('can generate text', function () {
    // Create a fake provider response
    $fakeResponse = new ProviderResponse(
        text: 'Hello, I am Claude!',
        toolCalls: [],
        usage: new Usage(10, 20),
        finishReason: FinishReason::Stop,
        response: ['id' => 'fake-1', 'model' => 'fake-model']
    );

    // Set up the fake
    $fake = Prism::fake([$fakeResponse]);

    // Run your code
    $response = Prism::text()
        ->using(Provider::Anthropic, 'claude-3-5-sonnet-latest')
        ->withPrompt('Who are you?')
        ->generate();

    // Make assertions
    expect($response->text)->toBe('Hello, I am Claude!');
});

Testing Multiple Responses

When testing conversations or tool usage, you might need to simulate multiple responses:

php
use EchoLabs\Prism\ValueObjects\Usage;
use EchoLabs\Prism\Providers\ProviderResponse;

it('can handle tool calls', function () {
    $responses = [
        new ProviderResponse(
            text: '',
            toolCalls: [
                new ToolCall(
                    id: 'call_1',
                    name: 'search',
                    arguments: ['query' => 'Latest news']
                )
            ],
            usage: new Usage(15, 25),
            finishReason: FinishReason::ToolCalls,
            response: ['id' => 'fake-1', 'model' => 'fake-model']
        ),
        new ProviderResponse(
            text: 'Here are the latest news...',
            toolCalls: [],
            usage: new Usage(20, 30),
            finishReason: FinishReason::Stop,
            response: ['id' => 'fake-2', 'model' => 'fake-model']
        ),
    ];

    $fake = Prism::fake($responses);
});

Testing Tools

When testing tools, you'll want to verify both the tool calls and their results. Here's a complete example:

php
use EchoLabs\Prism\Prism;
use EchoLabs\Prism\Enums\Provider;
use EchoLabs\Prism\ValueObjects\Usage;
use EchoLabs\Prism\Providers\ProviderResponse;

it('can use weather tool', function () {
    // Define the expected tool call and response sequence
    $responses = [
        // First response: AI decides to use the weather tool
        new ProviderResponse(
            text: '', // Empty text since the AI is using a tool
            toolCalls: [
                new ToolCall(
                    id: 'call_123',
                    name: 'weather',
                    arguments: ['city' => 'Paris']
                )
            ],
            usage: new Usage(15, 25),
            finishReason: FinishReason::ToolCalls,
            response: ['id' => 'fake-1', 'model' => 'fake-model']
        ),
        // Second response: AI uses the tool result to form a response
        new ProviderResponse(
            text: 'Based on current conditions, the weather in Paris is sunny with a temperature of 72°F.',
            toolCalls: [],
            usage: new Usage(20, 30),
            finishReason: FinishReason::Stop,
            response: ['id' => 'fake-2', 'model' => 'fake-model']
        ),
    ];

    // Set up the fake
    $fake = Prism::fake($responses);

    // Create the weather tool
    $weatherTool = Tool::as('weather')
        ->for('Get weather information')
        ->withStringParameter('city', 'City name')
        ->using(fn (string $city) => "The weather in {$city} is sunny with a temperature of 72°F");

    // Run the actual test
    $response = Prism::text()
        ->using(Provider::Anthropic, 'claude-3-5-sonnet-latest')
        ->withPrompt('What\'s the weather in Paris?')
        ->withTools([$weatherTool])
        ->generate();

    // Assert the correct number of API calls were made
    $fake->assertCallCount(2);

    // Assert tool calls were made correctly
    expect($response->steps[0]->toolCalls)->toHaveCount(1);
    expect($response->steps[0]->toolCalls[0]->name)->toBe('weather');
    expect($response->steps[0]->toolCalls[0]->arguments())->toBe(['city' => 'Paris']);

    // Assert tool results were processed
    expect($response->toolResults)->toHaveCount(1);
    expect($response->toolResults[0]->result)
        ->toBe('The weather in Paris is sunny with a temperature of 72°F');

    // Assert final response
    expect($response->text)
        ->toBe('Based on current conditions, the weather in Paris is sunny with a temperature of 72°F.');
});

Testing Structured Output

php
use EchoLabs\Prism\Prism;
use EchoLabs\Prism\ValueObjects\Usage;
use EchoLabs\Prism\Enums\FinishReason;
use EchoLabs\Prism\Providers\ProviderResponse;
use EchoLabs\Prism\Schema\ObjectSchema;
use EchoLabs\Prism\Schema\StringSchema;

it('can generate structured response', function () {
    $schema = new ObjectSchema(
        name: 'user',
        description: 'A user object, because we love organizing things!',
        properties: [
            new StringSchema('name', 'The user\'s name (hopefully not "test test")'),
            new StringSchema('bio', 'A brief bio (no novels, please)'),
        ],
        requiredFields: ['name', 'bio']
    );

    $fakeResponse = new ProviderResponse(
        text: json_encode([
            'name' => 'Alice Tester',
            'bio' => 'Professional bug hunter and code wrangler'
        ]),
        toolCalls: [],
        usage: new Usage(10, 20),
        finishReason: FinishReason::Stop,
        response: ['id' => 'fake-1', 'model' => 'fake-model']
    );

    $fake = Prism::fake([$fakeResponse]);

    $response = Prism::structured()
        ->using('anthropic', 'claude-3-sonnet')
        ->withPrompt('Generate a user profile')
        ->withSchema($schema)
        ->generate();

    // Assertions
    expect($response->object)->toBeArray();
    expect($response->object['name'])->toBe('Alice Tester')
    expect($response->object['bio'])->toBe('Professional bug hunter and code wrangler');
});

Assertions

Prism's fake implementation provides several helpful assertion methods:

php
// Assert specific prompt was sent
$fake->assertPrompt('Who are you?');

// Assert number of calls made
$fake->assertCallCount(2);

// Assert detailed request properties
$fake->assertRequest(function ($requests) {
    expect($requests[0]->provider)->toBe('anthropic');
    expect($requests[0]->model)->toBe('claude-3-sonnet');
});

// Assert provider configuration
$fake->assertProviderConfig(['api_key' => 'sk-1234']);

Released under the MIT License.