BrainMonkey icon indicating copy to clipboard operation
BrainMonkey copied to clipboard

How to use Brain Monkey to mock class methods?

Open remyperona opened this issue 5 years ago • 3 comments

This is more a question on the right use of expect than an issue.

I'm trying to test that a method was called, but I'm not sure I'm doing it right.

I have a dependency class with a purge method

namespace Vendor\Name;

class Dependency {
    public function purge( $url ) {}
}

And another class using this dependency and method in a clean_domain method

namespace Vendor\Name;

class Handler {
    public function __construct( Dependency $dependency ) {
        $this->dependency = $dependency;
    }

    public function clean_domain( $url ) {
        $this->dependency->purge( $url );
    }
}

In my tests I have the following test method

public function testShouldPurge() {
        $dependency = $this->createMock('Vendor\Name\Dependency');

        $handler = new Handler( $dependency );

        Functions\expect( 'Vendor\\Name\\purge' )
            ->times(1)
            ->withAnyArgs();

        $handler->clean_domain( 'http://example.org' );
    }

But am getting the error Mockery\Exception\InvalidCountException: Method Vendor_Name_Purge (<Any Arguments>) from Mockery_0 should be called exactly 1 times but called 0 times. when running the tests.

What am I missing here?

remyperona avatar Oct 08 '19 15:10 remyperona

Hi @Tabrisrp

Brain Monkey is a tool to mock functions, not class methods.

If you're using modern PHPUnit version, you've at least two options to mock class methods without Brain Monkey.

Built-in PHPUnit mock builder

The first is to make use of built-in PHPUnit mock builder:

public function testShouldPurge() {

    $url = 'http://example.org';

    $dependency = $this->getMockBuilder(\Vendor\Name\Dependency::class)
        ->setMethods(['purge'])
        ->getMock();

    $dependency
        ->expects($this->once())
        ->method('purge')
        ->with($this->equalTo($url));

    $handler = new Handler($dependency);

    $handler->clean_domain($url);
}

The documentation for more advanced usage can be found in PHPUnit docs.

Prophecy

The second option is to use Prophecy, which IIRC is included in PHPUnit since v6:

public function testShouldPurge() {

    $url = 'http://example.org';

    $dependency = $this->prophesize(\Vendor\Name\Dependency::class);
    $dependency->purge($url)->shouldBeCalled();

    $handler = new Handler($dependency->reveal());

    $handler->clean_domain($url);
}

Please refer to Prophecy docs for more advanced usage.

However, if you're using Brain Monkey, you've a 3rd option.

Mockery

Brain Monkey requires Mockery so, having it in you vendor folder, you can use it without much effort.

And if you're following the docs to setup tests for Brain Monkey, your tests are already setup to use it.

So you can also do something like this:

public function testShouldPurge() {

    $url = 'http://example.org';

    $dependency = \Mockery::mock(\Vendor\Name\Dependency::class);
    $dependency->shouldReceive('purge')->once()->with($url);

    $handler = new Handler($dependency);

    $handler->clean_domain($url);
}

As usual, please refer to Mockery docs for more advanced usage.

In test suites that use Brain Monkey, to use Mockery to mock class methods has the benefit to use same API for both class methods and functions (or WP hooks).

In fact, Brain Monkey at its core is a "bridge" between the function-redefinition feature provided by Patchwork and the mock capabilities of Mockery.

gmazzap avatar Oct 08 '19 16:10 gmazzap

I'm keeping this issue open, because I often got asked similar questions.

I will change the title for the benefit of people who'll come later.

gmazzap avatar Oct 08 '19 16:10 gmazzap

Thank you for the fast and detailed answer, using Mockery directly works perfectly in my case 👍

remyperona avatar Oct 08 '19 21:10 remyperona

Changed my mind about keeping issues open for answered questions. I guess if this is necessary it should be added to documentation.

gmazzap avatar Dec 12 '22 18:12 gmazzap