Mock should be called exactly 1 times but called 0 times
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Mastering Mockery: Solving the Exact Count Paradox in Laravel Testing
As senior developers working with the Laravel ecosystem, we often run into hurdles when trying to isolate components for unit testing. One of the most frustrating issues revolves around mocking facades and service interactions, especially when dealing with complex return types like closures or objects passed through the container. The error you encountered—Method send(...) should be called exactly 1 times but called 0 times—is a classic symptom of misunderstanding how Mockery tracks expectations and handles method calls within facades.
This post will dive deep into why this happens, dissect your specific test scenario involving Laravel's Mail facade, and provide robust strategies for mocking dependencies cleanly in your PHPUnit tests, keeping modern Laravel principles in mind.
The Mockery Philosophy: Stubbing vs. Mocking
Before addressing the specific error, it’s essential to understand Mockery’s core behavior. As you correctly noted, Mockery is fundamentally a stubbing library, not a full-blown mocking framework. This distinction is key:
- Stubbing: Setting up expectations on methods (e.g.,
shouldReceive('method')) tells the mock object what to return when that method is called. If you don't define an expectation, the method defaults to allowing any call (zero or more times). - Mocking: Creating a completely fake object that simulates a real class and its behavior.
When you use shouldReceive('method')->times(1), you are explicitly demanding exactly one invocation. If the code under test never actually invokes that specific method on the mocked facade, Mockery throws an InvalidCountException because the expected call count (1) did not match the actual call count (0).
Diagnosing the Facade Mocking Problem
Your setup involves mocking the Mail facade:
Mail::shouldReceive('send')
->with(
'emails.register',
['user' => $user],
function ($mail) use ($user) { /* ... logic to assert return values */ }
)
->times(1)
->andReturnUsing(function ($message) use ($user) {
// Assertion logic here
});
The difficulty often arises when mocking facades. Facades in Laravel are essentially static proxies that rely on the Service Container to resolve their underlying implementations (like Illuminate\Mail\Mailer). When you mock a facade method directly, you are mocking the interface of that interaction, not necessarily forcing the service container to execute its full dependency chain perfectly within the test context.
The error suggests that while you set up an expectation on the façade call, the code being tested (or the setup phase) is somehow bypassing the actual execution path where send is called with the exact arguments you specified.
The Solution: Focusing on Service Abstraction and Dependency Injection
Instead of trying to mock the static facade directly—which can be brittle across different Laravel versions—the most robust pattern, aligned with best practices promoted by the Laravel team, is to decouple your application logic from direct facade calls using Dependency Injection (DI).
For complex interactions like sending mail, you should inject an interface or a concrete implementation of the Mailer service into your class being tested, rather than relying solely on mocking static facades. This approach ensures that your tests focus on unit testing concrete classes, which is more stable and less prone to framework version conflicts.
Refactoring for Testability
If you are testing a class that uses Mail, consider injecting the necessary mailer service:
1. Define an Interface (or use existing contracts): Ensure your class accepts the Mailer interface in its constructor.
2. Inject the Mock: Pass your Mockery object into the constructor.
3. Test the Logic: Assert that when your method is called, it correctly delegates to the injected mock, verifying the interaction without relying on fragile facade mocking.
While direct facade mocking can sometimes be necessary for integration tests, for deep unit testing of business logic, focusing on dependency injection makes the test more reliable and aligns perfectly with the principles of building scalable applications showcased by resources like laravelcompany.com.
Conclusion
The InvalidCountException in your Mail mocking scenario stems from a mismatch between the