Test Laravel AI Systems with Zero API Calls | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. [Laravel](https://www.msaied.com/public/articles?category=laravel)
6. /
7. Ship AI with Laravel: Test Your AI System with Zero API Calls

   [Laravel](https://www.msaied.com/public/articles?category=laravel) [AI](https://www.msaied.com/public/articles?category=ai) 

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

 Learn how to test a full Laravel AI platform using Pest and the SDK's faking system — no real API calls, no cost, no flakiness. All 12 AI tests pass on every commit.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 27 Jun 2026 · Updated 30 Jun 2026 · 3 min read

ShareCopy linkCopied

 ![Ship AI with Laravel: Test Your AI System with Zero API Calls](https://cdn.msaied.com/331/52e9e0988d8c9a6dc40174a7c6256301.png) 

  On this page +1. [The Problem with Testing AI Code](#the-problem-with-testing-ai-code)
2. [Setting Up the Fake](#setting-up-the-fake)
3. [What Gets Tested](#what-gets-tested)
4. [Agent Prompting and Conversation Context](#agent-prompting-and-conversation-context)
5. [Preventing Accidental AI Calls](#preventing-accidental-ai-calls)
6. [Queued Prompts](#queued-prompts)
7. [Custom Tools Against Real Database Records](#custom-tools-against-real-database-records)
8. [Feature Testing the Chat Endpoint](#feature-testing-the-chat-endpoint)
9. [Vector Store and Knowledge Base](#vector-store-and-knowledge-base)
10. [The Result](#the-result)
11. [Key Takeaways](#key-takeaways)
12. [What's Next](#whats-next)

 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:

```php
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:

```php
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:

```php
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](https://youtu.be/r1F-fxVeehA) | ⭐ [GitHub Repository](https://github.com/harris21/ship-ai-with-laravel)

---

*Source: [Laravel News — Ship AI with Laravel: Test Your AI System with Zero API Calls](https://laravel-news.com/ship-ai-with-laravel-test-your-ai-system-with-zero-api-calls)*

- [Laravel](https://www.msaied.com/public/articles?search=Laravel)
- [AI Testing](https://www.msaied.com/public/articles?search=AI%20Testing)
- [Pest](https://www.msaied.com/public/articles?search=Pest)
- [PHP](https://www.msaied.com/public/articles?search=PHP)
- [OpenAI](https://www.msaied.com/public/articles?search=OpenAI)
- [TDD](https://www.msaied.com/public/articles?search=TDD)

 Frequently asked questions 
---------------------------

  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.

   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.

   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.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

[Mohamed Said](https://www.msaied.com/public#person)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleAdvanced Eloquent Casts: Custom Cast Classes, Value Objects, and Inbound-Only Transforms](https://www.msaied.com/public/articles/advanced-eloquent-casts-custom-cast-classes-value-objects-and-inbound-only-transforms) [Next articleAdvanced Authorization in Laravel: Gates, Policies, and Response-Based Access Control](https://www.msaied.com/public/articles/advanced-authorization-in-laravel-gates-policies-and-response-based-access-control-1)  

   On this page
-------------

1. [The Problem with Testing AI Code](#the-problem-with-testing-ai-code)
2. [Setting Up the Fake](#setting-up-the-fake)
3. [What Gets Tested](#what-gets-tested)
4. [Agent Prompting and Conversation Context](#agent-prompting-and-conversation-context)
5. [Preventing Accidental AI Calls](#preventing-accidental-ai-calls)
6. [Queued Prompts](#queued-prompts)
7. [Custom Tools Against Real Database Records](#custom-tools-against-real-database-records)
8. [Feature Testing the Chat Endpoint](#feature-testing-the-chat-endpoint)
9. [Vector Store and Knowledge Base](#vector-store-and-knowledge-base)
10. [The Result](#the-result)
11. [Key Takeaways](#key-takeaways)
12. [What's Next](#whats-next)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
