如何使用 Mockery 在模拟方法的第 N 次调用中引发异常

Posted

技术标签:

【中文标题】如何使用 Mockery 在模拟方法的第 N 次调用中引发异常【英文标题】:How to throw an exception on the Nth call of a mock method with Mockery 【发布时间】:2018-11-26 18:58:27 【问题描述】:

我需要测试我编写的某些代码在多次调用另一个类的方法时会如何表现,其中一个调用将导致抛出异常。

我正在使用Mockery 模拟可能引发异常的类。

所以在我的例子中,该方法将被调用 3 次,我需要它在第二次抛出异常。

这是我的意图示例,但它不起作用。

$mock = \Mockery::mock();
$mock->shouldReceive('fetch')
    ->andReturnUsing(
        function () return true;,
        function () use ($e) throw new \Exception();,
        function () return false;
    );

Asserting that mock throws exception · Issue #308 · mockery/mockery 中的回复给我的印象是上述可能有效。

但是,在实践中,以这种方式抛出异常会导致 Mockery 捕获异常并抛出自己的 BadMethodCall 异常。

【问题讨论】:

【参考方案1】:

我在 Mockery Github 问题中找到了答案,Mock multiple method call with return and throw。

$mock = \Mockery::mock();
$mock->shouldReceive('fetch')
    ->andReturnUsing(
        function () use () 
            static $counter = 0;

            switch ($counter++) 
                case 0:
                    return true;
                    break;
                case 1:
                    throw new \Exception();
                    break;
                default:
                    return false;
                    break;
            
        
    );

对于那些正在寻找使用 phpUnit 的解决方案的人...

$mockHydrator = $this->createMock(MyObject::class);
$mockHydrator->method('fetch')
    ->will(
        $this->onConsecutiveCalls(
            true,
            $this->throwException($e),
            false
        )
    );

这是我觉得 PHPUnit mocks 提供比 Mockery 更好的接口的一种情况。

【讨论】:

以上是关于如何使用 Mockery 在模拟方法的第 N 次调用中引发异常的主要内容,如果未能解决你的问题,请参考以下文章

Phpunit 在测试类中仅模拟一种方法 - 使用 Mockery

在 Mockery 中测试链式方法调用

使用 Mockery 模拟在另一个静态方法中调用的静态方法

如何使用 mockery 来模拟 httpclient

Mockery 无法使用 Eloquent 模型填充方法创建部分模拟

自称 PhpUnit / Mockery 的模拟方法