Lets say that I have the following interface:
interface MyInterface
{
public function yieldData();
}
I want to create a mock of this interface, for example like so:
$mocked_instance = Phake::partialMock(MyInterface::class);
What is the most preferred way to mock the yield method? This is the best that I came up with:
Phake::when($mocked_instance)->yieldData()->thenReturn([]);
Is there a way to do this in PHPUnit/Phake that more closely resembles the original functionality of the function (i.e. returning a Generator)?
Thank you Oliver Maksimovic for your comment, which has helped me in finding a solution that works for me.
I've decided to create the following function on my base testcase:
/*
* @param array @array
*
* @return \Generator|[]
*/
protected function arrayAsGenerator(array $array)
{
foreach ($array as $item) {
yield $item;
}
}
This allows me to do the following:
$mocked_instance = Phake::partialMock(MyInterface::class);
$numbers = [1, 2, 3, 4, 5];
Phake::when($mocked_instance)
->yieldData()
->thenReturn($this->arrayAsGenerator($numbers));
I'm using PHPUnit only, and didn't want to mess with adding Phake or other testing frameworks. The most useful solution to this problem I found came from this article:
https://www.gpapadop.gr/blog/2017/11/01/mocking-generators-in-phpunit/
However, I don't like the choice of syntax in the article, and I think it's easier to understand the code with a helper method, generate()
. Under the hood, it's still using the PHPUnit::returnCallback()
like in the article.
Here's an example Dependency class with a Generator method I need to mock:
class MockedClass
{
public function generatorFunc() : Generator
{
$values = [1,2,3,4];
foreach($values as $value)
{
yield $value;
}
}
}
And here's a PhpUnit Test class with a generate()
helper method that implements the solution in the article above:
class ExampleTest extends \PHPUnit\Framework\TestCase
{
// Helper function creates a nicer interface for mocking Generator behavior
protected function generate(array $yield_values)
{
return $this->returnCallback(function() use ($yield_values) {
foreach ($yield_values as $value) {
yield $value;
}
});
}
public function testMockedGeneratorExample()
{
$mockedObj = $this->createMock(MockedClass::class);
$mockedObj->expects($this->once())
->method('generatorFunc')
->will($this->generate([5,6,7,8]));
// Run code that uses MockedClass as dependency
// Make additional assertions as needed...
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With