Mockery & PHPUnit: method does not exist on this mock object
15,638
The error message seems clear to me. You only did setup a expectation for the put
method, but not exists
. The exists
method is called by the class under test in all code paths.
public function testGeneratorFire()
{
$fileMock = \Mockery::mock('\stats\jway\File');
$fileMock->shouldReceive('put')->with('foo.txt', 'foo bar')->once();
//Add the line below
$fileMock->shouldReceive('exists')->once()->andReturn(false);
$generator = new Generator($fileMock);
$generator->fire();
}
Author by
PeraMika
Updated on July 15, 2022Comments
-
PeraMika almost 2 years
Can you tell me where's the problem? I have a file GeneratorTest.php with the following tests:
<?php namespace stats\Test; use stats\jway\File; use stats\jway\Generator; class GeneratorTest extends \PHPUnit_Framework_TestCase { public function tearDown() { \Mockery::close(); } public function testGeneratorFire() { $fileMock = \Mockery::mock('\stats\jway\File'); $fileMock->shouldReceive('put')->with('foo.txt', 'foo bar')->once(); $generator = new Generator($fileMock); $generator->fire(); } public function testGeneratorDoesNotOverwriteFile() { $fileMock = \Mockery::mock('\stats\jway\File'); $fileMock->shouldReceive('exists') ->once() ->andReturn(true); $fileMock->shouldReceive('put')->never(); $generator = new Generator($fileMock); $generator->fire(); } }
and here are File and Generator classes:
File.php:
class File { public function put($path, $content) { return file_put_contents($path, $content); } public function exists($file_path) { if (file_exists($file_path)) { return true; } return false; } }
Generator.php:
class Generator { protected $file; public function __construct(File $file) { $this->file = $file; } protected function getContent() { // simplified for demo return 'foo bar'; } public function fire() { $content = $this->getContent(); $file_path = 'foo.txt'; if (! $this->file->exists($file_path)) { $this->file->put($file_path, $content); } } }
So, when I run these tests, I get the following message: BadMethodCallException: Method ... ::exists() does not exist on this mock object.
-
PeraMika almost 8 yearsOne question: when we create a Mock object like this:
$fileMock = \Mockery::mock('\stats\jway\File');
then all methods in that Mock object will returnNULL
by default, right?. If yes, then why we need to setupexists
method like you did, it will retun NULL and thereforeput
method will be executed anyway? -
Bram Gerritsen almost 8 yearsYou have to add
shouldIgnoreMissing()
to let the mock object return null when you didn't setup an expectation. In this case it would be better to be strict and return false, because a boolean value is what the interface ofexists
defines. If you rewriteif (! $this->file->exists($file_path))
toif ($this->file->exists($file_path) === false))
your unit test will break. -
alexw almost 7 years"You only did setup a expectation for the put method, but not exists. The exists method is called by the class under test in all code paths." Could you explain this more? Why do we need to set up test expectations for methods that are called incidentally?
-
Moses Ndeda over 6 years
shouldIgnoreMissing()
definitely helped me avoid some bottlenecks.