【问题标题】:Mock a method in the same class being tested模拟正在测试的同一类中的方法
【发布时间】:2011-08-13 07:52:02
【问题描述】:

我想在我正在测试的同一类中模拟一个方法。

ClassA {
   function hardToTest($arg) {
      // difficult to test code
   }

   function underTest() {
      return $this->hardToTest('foo');
   }
}

我在想我可以使用反射来做到这一点,但也许这只是我应该将hardToTest 移动到另一个对象的信号。

【问题讨论】:

  • 我使用的是 PhpUnit 5.7,我需要使用 createPartialMock 并指定需要模拟哪些方法。
  • 我同意必须在被测试的同一个类中模拟一个方法是代码异味,并且该方法应该移到另一个类中。

标签: php unit-testing mocking phpunit


【解决方案1】:

究竟是什么方法难以测试?

如果该方法受到保护,并且您真的很想测试它,那么您可以扩展您的 ClassA 并将 hardToTest($arg) 公开。

底线是你不应该仅仅因为你需要为它编写单元测试来修改这个类。通常,不应测试 privateprotected 方法 - 您应该只测试公共接口。

【讨论】:

  • 我需要测试一个调用同一类中另一个方法的方法。我希望能够在运行时模拟该方法的功能。将方法移动到另一个类不是我的首选。
  • 是的,这非常接近这个想法....创建一个被测系统的子类,并删除我不想测试的相关方法。感谢您的帮助
  • PlusOne 为你提底线
  • “底线是你不应该仅仅因为你需要为它编写单元测试来修改这个类。”无法进行单元测试的类(或代码)是写得不好的类(或代码)。
【解决方案2】:

如果underTest()'foo' 传递到hardToTest(),则此测试将成功。这在 PHPUnit 的文档中被称为 部分模拟,因为您只模拟了一些方法。

ClassATest {
    function testUnderTest() {
        $mock = $this->getMock('ClassA', ['hardToTest']);
        $mock->expects($this->once())
             ->method('hardToTest')
             ->with('foo');
        $mock->underTest();
    }
}

我同意你的直觉,这种需求可能是一种代码味道,告诉你这个类做得太多了。

PHPUnit 5.4+

由于 getMock() 在 5.4 中已弃用,请改用 getMockBuilder():。

$mock = $this->getMockBuilder('ClassA')
             ->setMethods(['hardToTest'])    // onlyMethods in 8.4+
             ->ge‌​tMock();

【讨论】:

  • 其实应该是$mock = $this->getMock('ClassA', [ 'hardToTest' ]);getMock的第二个参数应该是方法名数组。
  • 在某些情况下,您需要进行部分模拟,例如,如果其中一个类方法发出 HTTP 请求。最好模拟该方法并为请求返回一个存根。
  • @julestruong $this->getMockBuilder(class)->setMethods(['methodName'])->getMock();
  • 同意你的观点,这是一种代码味道。每当您必须从同一个类中模拟方法时,是时候考虑将其移至独立类中了。这将使您的测试更容易。我遭受了这个。
  • 你也可以使用$this->getMockBuilder('ClassA')->setConstructorArgs([$arg1, $arg2])
【解决方案3】:

我所采取的方法是创建一个待测系统的子类,并剔除相关方法。

【讨论】:

    猜你喜欢
    • 2021-09-17
    • 2014-07-20
    • 1970-01-01
    • 2019-04-04
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多