这种做法对phpunit好吗?

这种做法对phpunit好吗?,php,testing,phpunit,Php,Testing,Phpunit,当我编码时,我经常看到这样的东西: testMyMethod() { .... $mockMyServiceB ->expects($this->once()) ->method('myMethodA') ->with(myvalue1, myvalue2, myvalue3) ->willReturn($someMockResu

当我编码时,我经常看到这样的东西:

     testMyMethod() {
        ....
        $mockMyServiceB
            ->expects($this->once())
            ->method('myMethodA')
            ->with(myvalue1, myvalue2, myvalue3)
            ->willReturn($someMockResult);

        $myServiceA = new ServiceA($mockMyServiceB)
        $results = $myServiceA->something();

        $this->assertEquals(['resultA', 'resultB'], results);            
     }
  testMyMethodUseServiceBCorrectly() {
      ....
      // this time no WillReturn, just focus on how is used
      $mockMyServiceB
          ->expects($this->once())
          ->method('myMethodA')
          ->with(myvalue1, myvalue2, myvalue3);

      $myServiceA = new ServiceA($mockMyServiceB)
      $myServiceA->something(); 
 }


  testMyMethodUseServiceResults() {
      ....
      // this time no Expects() or With(), just focus on results
      $mockMyServiceB
          ->method('myMethodA') 
          ->willReturn(myvalue1, myvalue2, myvalue3);

      $myServiceA = new ServiceA($mockMyServiceB)
      $this->assertEquals(['resultA', 'resultB'], $myServiceA->something());
 }
不确定,但我认为随着编写越来越多的测试,这会使它们很快变得易读。你只是放了太多的信息(期望与回报混合)。您需要了解每个测试的参数顺序、期望值、执行顺序和返回值……我想太多了

我在考虑将代码转移到某个地方,在那里您只需测试myMethodA的正确使用,然后在另一个测试中,您可以只关注结果,如下所示:

     testMyMethod() {
        ....
        $mockMyServiceB
            ->expects($this->once())
            ->method('myMethodA')
            ->with(myvalue1, myvalue2, myvalue3)
            ->willReturn($someMockResult);

        $myServiceA = new ServiceA($mockMyServiceB)
        $results = $myServiceA->something();

        $this->assertEquals(['resultA', 'resultB'], results);            
     }
  testMyMethodUseServiceBCorrectly() {
      ....
      // this time no WillReturn, just focus on how is used
      $mockMyServiceB
          ->expects($this->once())
          ->method('myMethodA')
          ->with(myvalue1, myvalue2, myvalue3);

      $myServiceA = new ServiceA($mockMyServiceB)
      $myServiceA->something(); 
 }


  testMyMethodUseServiceResults() {
      ....
      // this time no Expects() or With(), just focus on results
      $mockMyServiceB
          ->method('myMethodA') 
          ->willReturn(myvalue1, myvalue2, myvalue3);

      $myServiceA = new ServiceA($mockMyServiceB)
      $this->assertEquals(['resultA', 'resultB'], $myServiceA->something());
 }

我认为这清楚地说明了您正在测试什么,并且生成了更小的测试。但不确定是否也是常见的……这是推荐的做法?

您仍然可以使用受保护或私有方法来配置模拟。例如,我们有一个项目,它有一个
类BaseTestCase扩展TestCase
和一个基本的
createMock($classname)
方法,从中扩展所有单元测试,以便为大多数模拟建筑使用一些代码

请记住,编写可读的测试代码时,要清楚地列出变量和方法的名称,并在可能的情况下重用代码


另外,请记住,如果您的测试越来越大,可能您需要重构您的类并获得一些简化的服务。

您仍然可以使用受保护的或私有的方法来配置mock。例如,我们有一个项目,它有一个
类BaseTestCase扩展TestCase
和一个基本的
createMock($classname)
方法,从中扩展所有单元测试,以便为大多数模拟建筑使用一些代码

请记住,编写可读的测试代码时,要清楚地列出变量和方法的名称,并在可能的情况下重用代码


另外,请记住,如果您的测试越来越大,可能需要重构您的类并获得一些简化的服务。

这里有几点需要改进:

  • 将创建已测试服务的实例移动到setUp()方法中

  • 使用数据提供程序将测试与数据分开


  • 然后测试将看起来像传统的PHPunit测试。此外,当您在数据提供程序()中正确命名测试用例时,数据提供程序将增加很多可读性和透明度。

    这里有几点需要改进:

  • 将创建已测试服务的实例移动到setUp()方法中

  • 使用数据提供程序将测试与数据分开


  • 然后测试将看起来像传统的PHPunit测试。此外,当您在数据提供程序()中正确命名测试用例时,数据提供程序将增加很多可读性和透明度。

    我建议不要在
    setUp()
    中设置正在测试的系统。它的优点可能是减少了一点重复,但缺点是如果不同时查看测试和
    setUp()
    ,就无法理解测试的功能。最终,您将面临这样的挑战:您希望在各个测试中以不同的方式注入和模拟SUT的依赖关系,然后事情变得越来越不容易理解。我建议大家看看。谢谢,这是一个关于潮湿和干燥的非常有趣的讨论。事实上,我支持这两个概念。在设置的情况下,我通常会把“新服务($this->dependencyOne,$this->dependencyTwo)”放在那里。因为如果您为服务编写单元测试,您无论如何都需要这一行。然后在测试方法内部-您定义了在$this->dependencyOne,$this->dependencytwo中要模拟的内容为否决投票道歉,我正在回复!我建议不要在
    setUp()
    中设置被测系统。它的优点可能是减少了一点重复,但缺点是如果不同时查看测试和
    setUp()
    ,就无法理解测试的功能。最终,您将面临这样的挑战:您希望在各个测试中以不同的方式注入和模拟SUT的依赖关系,然后事情变得越来越不容易理解。我建议大家看看。谢谢,这是一个关于潮湿和干燥的非常有趣的讨论。事实上,我支持这两个概念。在设置的情况下,我通常会把“新服务($this->dependencyOne,$this->dependencyTwo)”放在那里。因为如果您为服务编写单元测试,您无论如何都需要这一行。然后在测试方法内部-您定义了在$this->dependencyOne,$this->dependencytwo中要模拟的内容为否决投票道歉,我正在回复!简短的回答作为评论:视情况而定!我建议为每个执行路径编写完整的测试。您的示例表明您正在编写不完整的测试。问题是,如果你这样做,你可能会有较短的测试方法,但它们不能揭示全部情况。您可能能够使单个测试通过,但实际上,相应的生产代码并没有达到预期的效果。实际上做TDD总是更容易、更好。如果您的测试变得太大,它们可能意味着重构的机会。这些指标比短期测试更重要。嗨,谢谢你的回答。它给了我一个有趣的观点和意义。我可以看出,我可以将期望与资产分开,因为它们测试不同的行为,但正如您所说的,我应该尝试测试整个执行路径,感谢您的想法。简短的回答作为评论:这取决于!我建议为每个执行路径编写完整的测试。您的示例表明您正在编写不完整的测试。问题是,如果你这样做,你可能会有较短的测试方法,但它们不能揭示全部情况。您可能能够使单个测试通过,但实际上,相应的生产代码并没有达到预期的效果。实际上做TDD总是更容易、更好。如果您的测试变得太大,它们可能意味着重构的机会。这些指标比短期测试更重要。嗨,谢谢你的回答。它给了我一个有趣的v点