【问题标题】:PHP Unit Test Mocking a member variable dependencyPHP单元测试模拟成员变量依赖
【发布时间】: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 的不同变体,但我总是以异常结束。

我在这里做错了什么?

【问题讨论】:

    标签: unit-testing mocking phpunit mockery


    【解决方案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。我的答案中的测试用例适用于您问题中显示的 AB 类。
    猜你喜欢
    • 2016-02-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 2017-09-25
    • 2022-10-15
    • 2016-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多