PHP单元测试模拟成员变量依赖
Posted
技术标签:
【中文标题】PHP单元测试模拟成员变量依赖【英文标题】:PHP Unit Test Mocking a member variable dependency 【发布时间】:2021-02-28 18:40:54 【问题描述】:您好,假设我想测试从 A 类运行的函数,我正在使用 Mockery 模拟外部依赖项:
class A
protected myB;
public function __construct(B $param)
$this->myB = $param;
protected function doStuff()
return "done";
public function run()
$this->doStuff();
$this->myB->doOtherStuff();
return "finished";
class B
public function doOtherStuff()
return "done";
所以我写了这样的测试:
public function testRun()
$mockB = Mockery::mock('overload:B');
$mockB->shouldReceive('doOtherStuff')
->andReturn("not done");
$mockA = Mockery::mock(A::class)->makePartial()->shouldAllowMockingProtectedMethods();
$mockA->shouldReceive('doStuff')->andReturns("done");
$mockA->run();
这会引发这样的异常: 错误:在 null 上调用成员函数 doStuff()
我尝试了模拟在运行函数中调用的内部依赖项 B 的不同变体,但我总是以异常结束。
我在这里做错了什么?
【问题讨论】:
【参考方案1】:不要嘲笑你正在测试的东西。将模拟的B
注入A
。
public function testRun()
// Arrange
$mockB = Mockery::mock(B::class);
$a = new A($mockB);
// Assert
$mockB->shouldReceive('doOtherStuff')
->once()
->andReturn("not done");
// Act
$a->run();
如果你想猴子补丁A
,你仍然可以在(more details: constructor arguments in mockery)中传递模拟的B
:
public function testRun()
// Arrange
$mockB = Mockery::mock(B::class);
$a = Mockery::mock(A::class, [$mockB])
->makePartial()
->shouldAllowMockingProtectedMethods();
$a->shouldReceive('doStuff')
->andReturns('mocked done');
// Assert
$mockB->shouldReceive('doOtherStuff')
->once()
->andReturn('not done');
// Act
$a->run();
【讨论】:
但是如果我明确地想从 A 模拟一些函数而不是使用真实的函数呢? 基本一样。您仍然可以注入依赖项。我更新了我的答案。希望这会有所帮助。 我也尝试了这个解决方案,但它给了我这样的错误:Mockery\Exception\BadMethodCallException: Received Mockery_4_B::doOtherStuff(),但没有指定期望 如果我想让 mockB 部分化,那么它会尝试调用真正的 doOtherStuff 函数而不是模拟的函数。我真的不明白这里的行为Mockery_4_B
中的 4 告诉我,周围的模拟对象比本示例中的要多。也许你已经嘲笑了B
两次,并在没有期望的情况下将B
注入A
。我的答案中的测试用例适用于您问题中显示的 A
和 B
类。以上是关于PHP单元测试模拟成员变量依赖的主要内容,如果未能解决你的问题,请参考以下文章