使用PHPUnit/Phake模拟一个在PHP中返回Generator的函数

Thi*_*eek 6 php phpunit unit-testing generator phake

可以说我有以下界面:

interface MyInterface
{
    public function yieldData();
}
Run Code Online (Sandbox Code Playgroud)

我想创建一个这个界面的模拟,例如:

$mocked_instance = Phake::partialMock(MyInterface::class);
Run Code Online (Sandbox Code Playgroud)

模拟yield方法的最佳方法是什么?这是我想出的最好的:

Phake::when($mocked_instance)->yieldData()->thenReturn([]);
Run Code Online (Sandbox Code Playgroud)

有没有办法在PHPUnit/Phake中实现这一点,它更接近函数的原始功能(即返回Generator)?

Thi*_*eek 8

感谢Oliver Maksimovic的评论,这帮助我找到了适合我的解决方案。

我决定在我的基本测试用例上创建以下函数:

/*
 * @param array @array
 *
 * @return \Generator|[]
 */
protected function arrayAsGenerator(array $array)
{
    foreach ($array as $item) {
        yield $item;
    }
}
Run Code Online (Sandbox Code Playgroud)

这使我可以执行以下操作:

$mocked_instance = Phake::partialMock(MyInterface::class);

$numbers = [1, 2, 3, 4, 5];

Phake::when($mocked_instance)
    ->yieldData()
    ->thenReturn($this->arrayAsGenerator($numbers));
Run Code Online (Sandbox Code Playgroud)


Adi*_*din 6

我只使用 PHPUnit,并且不想添加 Phake 或其他测试框架。我发现这个问题最有用的解决方案来自这篇文章:

https://www.gpapadop.gr/blog/2017/11/01/mocking-generators-in-phpunit/

但是,我不喜欢文章中语法的选择,并且我认为使用辅助方法generate(). 在幕后,它仍然使用PHPUnit::returnCallback()文章中的类似内容。

这是一个示例依赖类,其中包含我需要模拟的生成器方法:

class MockedClass 
{
    public function generatorFunc() : Generator
    {
        $values = [1,2,3,4];

        foreach($values as $value)
        {
            yield $value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个 PhpUnit Test 类,其中包含一个generate()实现上述文章中的解决方案的辅助方法:

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...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,一个很好的建议。作为旁注:您的“generate”函数可以简化为:``protected functiongenerate(array $yield_values) {yield from $yield_values; } ``` (2认同)