Ship AI with Laravel: Test Your AI System with Zero API Calls
Laravel AI #Laravel #AI Testing #Pest #PHP #OpenAI #TDD

Ship AI with Laravel: Test Your AI System with Zero API Calls

3 min read Mohamed Said Mohamed Said

The Problem with Testing AI Code

Testing code that calls an external AI API is painful. Hitting OpenAI in your test suite is slow, costs money on every run, and returns non-deterministic responses — making stable assertions nearly impossible. If you've been skipping AI tests for these reasons, this episode of the Ship AI with Laravel series shows you a better path.

Using Pest and the Laravel AI SDK's built-in faking system, you can test your entire AI platform without a single real API call. The pattern mirrors how Laravel already handles faking mail, notifications, and queues — define responses up front, then assert the right prompts went out.

Setting Up the Fake

The SDK's faking system lets you swap out real AI calls with pre-defined responses in your test setup. This gives you deterministic output every time:

use Prism\Prism;

Prism::fake([
    'This ticket is about a billing issue.',
]);

With the fake in place, your agent, tools, and middleware all execute their real logic — only the external HTTP call is intercepted.

What Gets Tested

Agent Prompting and Conversation Context

The first set of tests verifies that the agent receives the correct prompt and that conversation history is passed through properly. Because responses are fixed, assertions on the returned content are stable across every run.

Preventing Accidental AI Calls

preventStrayPrompts() is a safety net that causes a test to fail if an AI call fires in a flow that should never trigger the agent — for example, during basic ticket creation:

Prism::preventStrayPrompts();

// Any unexpected AI call in this flow will now throw
$this->post('/tickets', $payload);

This catches regressions where a refactor accidentally introduces an AI call where none was intended.

Queued Prompts

For background classification jobs, you can assert that a queued prompt is dispatched on a valid submission and stays out of the queue on an invalid one:

Queue::fake();

$this->post('/tickets', $validPayload);

Queue::assertPushed(TicketClassifier::class);

Custom Tools Against Real Database Records

Custom tools are tested directly against real database records seeded in the test. A failing test in this episode caught a factory mismatch live — exactly the kind of regression a test suite is supposed to surface.

Feature Testing the Chat Endpoint

The chat endpoint is covered for authentication, request validation, and correct agent interaction, all without touching OpenAI.

Vector Store and Knowledge Base

Store creation, document uploads, and embedding generation are all faked, letting you assert the full knowledge-base seeding flow without any external calls.

The Result

All 12 AI tests pass, run in seconds, and never touch an external API. You can run them on every commit without worrying about cost or flakiness.

Key Takeaways

  • The Laravel AI SDK ships a faking system that works just like Mail::fake() or Queue::fake().
  • preventStrayPrompts() guards flows that should never trigger an AI call.
  • Queued AI jobs can be asserted with Queue::fake() the same way as any other job.
  • Custom tools should be tested against real seeded records to catch factory mismatches early.
  • Feature tests cover auth, validation, and agent interaction without any API cost.
  • Deterministic faked responses make assertions reliable across every CI run.

What's Next

The next episode moves into security — protecting the agent against prompt injection by screening every incoming message with a local LLM before it reaches OpenAI, with zero API cost on blocked requests.

📺 Watch Episode 10 on YouTube | ⭐ GitHub Repository


Source: Laravel News — Ship AI with Laravel: Test Your AI System with Zero API Calls

Found this useful?

Frequently Asked Questions

3 questions
Q01 How do you fake AI API calls in Laravel tests?
The Laravel AI SDK provides a faking system similar to `Mail::fake()` or `Queue::fake()`. You call `Prism::fake([...])` with an array of pre-defined responses before your test runs. The agent and tools execute their real logic, but no HTTP request is made to OpenAI or any other provider.
Q02 What does preventStrayPrompts() do in Laravel AI tests?
`preventStrayPrompts()` causes a test to fail immediately if an AI prompt fires in a code path where none is expected. It acts as a regression guard — if a refactor accidentally introduces an AI call into a flow like basic ticket creation, the test suite will catch it.
Q03 Can queued AI classification jobs be tested without real API calls?
Yes. Combine `Queue::fake()` with `Prism::fake()` to assert that a job such as `TicketClassifier` is pushed onto the queue for valid input and not pushed for invalid input, all without dispatching real jobs or making API calls.

Continue reading

More Articles

View all