BrainMonkey
BrainMonkey copied to clipboard
How to use Brain Monkey to mock class methods?
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?
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.
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.
Thank you for the fast and detailed answer, using Mockery directly works perfectly in my case 👍
Changed my mind about keeping issues open for answered questions. I guess if this is necessary it should be added to documentation.