Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

shadrix's avatar
Level 12

How to use Mockery for a class used in a controller?

Let's say my controller looks like that.

public function store()
{
    Newsletter::subscribePending($email);
}

And Newsletter is a Class to use MailChimps Api easier.

Now how do I write a test for it?

I tried this, but it does not work. (I'm new to Mockery and it sends the data to mailchimp).

use Spatie\Newsletter\Newsletter;
class NewsletterTest extends TestCase {

    use RefreshDatabase;

    public function setUp()
    {
        parent::setUp();

        \Mockery::mock(Newsletter::class);
    }

    public function tearDown() {
        \Mockery::close();
    }


    /** @test */
    public function a_guest_can_subscribe_to_newsletter() 
    {
        $this->withoutExceptionHandling();
        $this->json('post', route('newsletter.store'), ['email' => '[email protected]'])
             ->assertStatus(201);
    }
}
0 likes
3 replies
shadrix's avatar
Level 12

Ah I see I need to use something like that

 $this->mock = \Mockery::mock(Newsletter::class);

 $this->app->instance(Newsletter::class, $this->mock);

I'm getting on a right track.

Talinon's avatar
Talinon
Best Answer
Level 51

I think you're under the impression that Mockery wields some magic where it can alter your source code with a mock. This is not the case - your test post will still execute your source code exactly as you have it.

Instead, in your test, you can swap out the underlying Newsletter class by calling swap() on the facade.

use Spatie\Newsletter\Newsletter;
class NewsletterTest extends TestCase {

    use RefreshDatabase;

    public function setUp()
    {
        parent::setUp();
    }

    public function tearDown() {
        \Mockery::close();
    }


    /** @test */
    public function a_guest_can_subscribe_to_newsletter() 
    {

    $mock = \Mockery::mock(Newsletter::class)->shouldReceive('subscribePending')->once();  

    \Newsletter::swap($mock);

        $this->json('post', route('newsletter.store'), ['email' => '[email protected]'])
             ->assertStatus(201);
    }
}

The above test will swap your underlying Newsletter class with a mock (for the duration of the test), that expects the function subscribePending to be called exactly once. If the function doesn't get called, Mockery will throw Mockery\Exception\InvalidCountException

Keep in mind, this does not test anything, other than the fact that at some point in your stack, Newsletter::subscribePending() gets called.

You could do the same with a service provider, or anything bound in the Laravel Service Container.

    $mock = Mockery::mock('someClass'); // chain on method calls
    app()->instance('someClass', $mock); // bind the mock object into the Service Container

Now whenever 'someClass' gets resolved out of the Container, it will be your mock, not your source object.

Hope this helps you better understand how Mockery works.

2 likes
shadrix's avatar
Level 12

@Talinon thanks! It helps me a lot. Mockery is super weird to understand, especially because I didn't need it until now. Thank you again!

Please or to participate in this conversation.