logo

Can you mock a trait?

Yes, but it probably won't help

Joel Clermont
Joel Clermont
2026-11-12

Imagine a class that pulls in a trait to send notifications to an external service.

trait SendsNotifications
{
    public function sendNotification(string $message): void
    {
        // calls an external service
    }
}

class OrderProcessor
{
    use SendsNotifications;

    public function complete(): void
    {
        // process the order...
        $this->sendNotification('Order completed!');
    }
}

You don't want your test sending real notifications, so can you mock the trait?

Technically, yes. Mockery will generate a class that uses the trait, and you can stub its methods.

$mock = Mockery::mock(SendsNotifications::class);

That's handy for testing the trait on its own, but it doesn't help here. The mock isn't an OrderProcessor, and you can't type-hint a trait, so there's no way to swap it into the code you're testing.

What you can do is partially mock the class that uses the trait. Trait methods become part of the class, so you can stub just that one method.

$processor = Mockery::mock(OrderProcessor::class)->makePartial();
$processor->shouldReceive('sendNotification')->once()->with('Order completed!');

$processor->complete();

This works, but now you're mocking part of the very class you're testing. And partial mocks come with their own quirks, like not running the constructor.

Wanting to mock a trait can be a sign the behavior belongs in its own class. Move it into a service and inject it.

class OrderProcessor
{
    public function __construct(protected NotificationService $notifications) {}

    public function complete(): void
    {
        // process the order...
        $this->notifications->send('Order completed!');
    }
}

Now the test mocks a real dependency through the container, like any other service.

$this->mock(NotificationService::class)
    ->shouldReceive('send')
    ->once()
    ->with('Order completed!');

app(OrderProcessor::class)->complete();

Traits are still great for sharing behavior, like our HasNoRules trait for form requests. What pushed this one into a class was the external call, since a dependency you inject is one you can swap out in a test.

Here to help,

Joel

P.S. Our testing course covers testing a service class on its own, and mocking that service everywhere else it's used.

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼
email
No spam. Only real-world advice.