Are you an LLM? You can read better optimized documentation at /laravel-executable/1.x/testing/mocking-and-spying.md for this page in Markdown format
Mocking & Spying
Mocking and spying require Mockery, which is included with Laravel's default test dependencies.
Mocking
Replace execution entirely:
php
it("sends welcome email on registration", function () {
SendWelcomeEmail::mock()->shouldExecute()->once()->with($user);
$service->registerUser($user);
// Mockery verifies the expectation automatically
});
it("returns a custom value from the mock", function () {
CalculatePrice::mock()->shouldExecute()->andReturn(42.5);
$result = $service->getPrice($product);
expect($result)->toBe(42.5);
});
it("never sends email for inactive users", function () {
SendWelcomeEmail::mock()->shouldNeverExecute();
$service->registerInactiveUser($user);
});The mock registers in the container, so any code that resolves the executable through ::sync(), ::onQueue(), or dependency injection gets the mock. Direct instantiation with new bypasses the container and won't use the mock.
Spying
Real execution + assertions after:
php
it("processes the order", function () {
ProcessOrder::spy();
$service->handleOrder($order);
ProcessOrder::assert()->executed()->once()->with($order);
});
it("processes multiple orders", function () {
ProcessOrder::spy();
$service->handleOrders([$orderA, $orderB]);
ProcessOrder::assert()->executed()->twice();
});
it("never processes cancelled orders", function () {
ProcessOrder::spy();
$service->handleCancelledOrder($order);
ProcessOrder::assert()->notExecuted();
});
it("never processes with specific arguments", function () {
ProcessOrder::spy();
$service->handleOrders([$orderA, $orderB]);
// Assert it was never called with this specific order
ProcessOrder::assert()->notExecuted()->with($cancelledOrder);
// Or use a callback for more complex matching
ProcessOrder::assert()->notExecuted()->withArgs(fn($order) => $order->status === "cancelled");
});Spies let the real execute() run. Use them when you want to verify the call happened without replacing behavior.
The executed() chain proxies to Mockery's verification API. Any Mockery verification method works (once(), twice(), times(), with(), withArgs(), ordered(), etc.).
