如何在PHPUnit中的while循环中进行单元测试?

时间:2018-12-03 20:08:23

标签: php phpunit phpunit-testing

我有一个Service类和一个测试类,请按照以下步骤操作:

课程

class MyCustomService
{
    public function job()
    {
       while($this->getResponseFromThirdPartyApi()->data) {
            // do some stuff...
       }    
       return ...
    }

    protected function getResponseFromThirdPartyApi()
    {
        // Here do some curl and return stdClass
        // data attribute is populated only on first curl request
    }
}

测试模拟getResponseFromThirdPartyApi方法

class MyCustomServiceTest
{
    public function testJobImportingData()
    {
        $myCustomServiceMock = $this->getMockBuilder('MyCustomService')
        ->setMethods(array('getResponseFromThirdPartyApi'))
        ->getMock();

        $myCustomServiceMock->expects($this->any())
            ->method('getResponseFromThirdPartyApi')
            ->willReturn($this->getResponseWithData());

        $jobResult = $myCustomServiceMock->job();

        // here some assertions on $jobResult
    }

    protected function getResponseWithData()
    {
        $response = new \stdClass;
        $response->data = ['foo', 'bar'];

        return $response;
    }
}

在第一次调用MyCustomService的while循环后,如何更改getResponseWithData返回?

我尝试在MyCustomServiceTest上创建自定义标志并检查getResponseWithData,但是一旦该模拟对象不再在MyCustomServiceTest上再次调用getResponseWithData方法,则会失败。

任何方向?

1 个答案:

答案 0 :(得分:0)

正如Nico Haase上面建议的那样,路径是使用回调。

经过一些研究,我实现了将模拟对象引用传递给模拟方法并检查标志,结果如下:

class MyCustomServiceTest
{
    public function testJobImportingData()
    {
        $myCustomServiceMock = $this->getMockBuilder('MyCustomService')
        ->setMethods(array('getResponseFromThirdPartyApi'))
        ->getMock();

        $myCustomServiceMock->expects($this->any())
            ->method('getResponseFromThirdPartyApi')
            ->will($this->returnCallback(
                function () use ($myCustomServiceMock) {
                    return $this->getResponseWithData($myCustomServiceMock)
                }
            ));

        $jobResult = $myCustomServiceMock->job();

        // here some assertions on $jobResult
    }

    protected function getResponseWithData(&$myCustomServiceMock)
    {
        $response = new \stdClass;

        if (isset($myCustomServiceMock->imported)) {
            $response->data = false;
            return $response;
        }

        $myCustomServiceMock->imported = true;

        $response = new \stdClass;
        $response->data = ['foo', 'bar'];

        return $response;
    }
}

然后while循环将仅被调用一次,我们将能够进行无永久循环的测试。