【问题标题】:PHPUnit: how to mock multiple method calls with multiple arguments and no straight order?PHPUnit:如何模拟具有多个参数且没有直接顺序的多个方法调用?
【发布时间】:2017-03-01 01:32:01
【问题描述】:

我需要测试以下功能:

[...]
public function createService(ServiceLocatorInterface $serviceManager)
{

    $firstService = $serviceManager->get('FirstServiceKey');
    $secondService = $serviceManager->get('SecondServiceKey');

    return new SnazzyService($firstService, $secondService);
}
[...]

我知道,我可能会这样测试:

class MyTest extends \PHPUnit_Framework_TestCase
{
    public function testReturnValue()
    {
        $firstServiceMock = $this->createMock(FirstServiceInterface::class);
        $secondServiceMock = $this->createMock(SecondServiceInterface::class);

        $serviceManagerMock = $this->createMock(ServiceLocatorInterface::class);

        $serviceManagerMock->expects($this->at(0))
             ->method('get')
             ->with('FirstServiceKey')
             ->will($this->returnValue($firstService));

        $serviceManagerMock->expects($this->at(1))
             ->method('get')
             ->with('SecondServiceKey')
             ->will($this->returnValue($secondServiceMock));

        $serviceFactory = new ServiceFactory($serviceManagerMock);

        $result = $serviceFactory->createService();
    }
    [...]

[...]
public function testReturnValue()
{
    $firstServiceMock = $this->createMock(FirstServiceInterface::class);
    $secondServiceMock = $this->createMock(SecondServiceInterface::class);

    $serviceManagerMock = $this->createMock(ServiceLocatorInterface::class);

    $serviceManagerMock->expects($this->any())
         ->method('get')
         ->withConsecutive(
            ['FirstServiceKey'],
            ['SecondServiceKey'],
         )
         ->willReturnOnConsecutiveCalls(
            $this->returnValue($firstService),
            $this->returnValue($secondServiceMock)
         );

    $serviceFactory = new ServiceFactory($serviceManagerMock);

    $result = $serviceFactory->createService();
}
[...]

两者都可以正常工作,但如果我在 createService 函数中交换 ->get(xxx) 行,两个测试都会失败。 那么,我该如何更改不需要特定序列的测试用例参数'FirstServiceKey','SecondServiceKey,......

【问题讨论】:

  • 你试过用$this->any()代替$this->at(0)吗?
  • 是的,那是我的第一次尝试。导致错误:调用零次或多次时,方法名称的期望失败等于 调用参数 0
  • 是的,最初我没有仔细阅读您的问题。希望我的回答能满足你的需要

标签: unit-testing zend-framework2 phpunit


【解决方案1】:

您可以尝试使用willReturnCallbackwillReturnMap 策略,例如willReturnCallback

public function testReturnValue()
{
    $firstServiceMock = $this->createMock(FirstServiceInterface::class);
    $secondServiceMock = $this->createMock(SecondServiceInterface::class);

    $serviceManagerMock = $this->createMock(ServiceLocatorInterface::class);


    $serviceManagerMock->expects($this->any())
        ->method('get')
        ->willReturnCallback(
            function ($key) use($firstServiceMock, $secondServiceMock) {
                if ($key == 'FirstServiceKey') {
                    return $firstServiceMock;
                }
                if ($key == 'SecondServiceKey') {
                    return $secondServiceMock;
                }
                throw new \InvalidArgumentException; // or simply return;
            }
        );

    $serviceFactory = new ServiceFactory($serviceManagerMock);

    $result = $serviceFactory->createService();
}

希望有帮助

【讨论】:

    【解决方案2】:

    已经有一段时间了,所以有一个新选项可以解决这个问题:更改为“先知”

    public function testReturnValue()
    {
        $this->container = $this->prophesize(ServiceLocatorInterface::class);
        $firstService = $this->prophesize(FirstServiceInterface::class);
        $secondService = $this->prophesize(SecondServiceKey::class);
    
        $this->container->get('FirstServiceKey')->willReturn(firstService);
        // And if you like
        $this->container->get('FirstServiceKey')->shouldBeCalled();
    
        $this->container->get('SecondServiceKey')->willReturn(secondService);
        [...]
        $serviceFactory = new ServiceFactory();
    
        /*
         * Little error in my example. ServiceLocatorInterface is parameter of 
         * createService() and not the constructor ;) (ZF2/3)
         */
    
        $result = $serviceFactory->createService(
            $this->container->reveal()
        );
        [...]
    }   
    

    现在,你将按照哪个顺序创建 '$serviceManager->get([...]);' 并不重要调用 \o/

    【讨论】:

      猜你喜欢
      • 2012-06-12
      • 2014-05-05
      • 2011-08-15
      • 1970-01-01
      • 1970-01-01
      • 2011-10-14
      • 2021-11-01
      • 2011-07-25
      • 1970-01-01
      相关资源
      最近更新 更多