phpunit 必须是可遍历的或实现接口 Iterator

phpunit must be traversable or implement interface Iterator

我正在尝试对我的服务进行单元测试,其中包含 symfony2(http://symfony.com/doc/current/components/finder.html) 的依赖项查找器组件。

我得到:

[Exception] Objects returned by Mock_Finder_91776c5c::getIterator() must be traversable or implement interface Iterator

服务:

public function getFile($fileName, $path = '/')
    {

        if($this->wrapper == null || $this->connection == null)
            throw new LogicException("call method setFTP first");

        // get file on ftp server
        $this->connection->open();
        $downloadComplete = $this->wrapper->get($this->tmpDir . $fileName, $path . $fileName);
        $this->connection->close();

        if($downloadComplete == false)
            return false; // TODO exception ?

        // return file downloaded
        $this->finder->files()->in(__DIR__);
        foreach ($this->finder as $file) {
            return $file;
        }

        return false; // TODO exception ?

    }

和测试

class FtpServiceTest extends \PHPUnit_Framework_TestCase
{

    protected $connectionMock;
    protected $ftpWrapperMock;
    protected $finderMock;

    protected function setUp()
    {
        $this->connectionMock = $this->getConnectionMock();
        $this->ftpWrapperMock = $this->getFTPWrapperMock();
        $this->finderMock = $this->getFinderMock();
    }

    protected function tearDown()
    {
    }

    private function getFinderMock()
    {
        return $this->getMockBuilder(Finder::class)
            ->disableOriginalConstructor()
            ->getMock('Iterator');
    }

    private function getConnectionMock()
    {
        return $this->getMockBuilder(Connection::class)
            ->disableOriginalConstructor()
            ->getMock();
    }

    private function getFTPWrapperMock()
    {
        return $this->getMockBuilder(FTPWrapper::class)
            ->disableOriginalConstructor()
            ->getMock();
    }

    // tests
    public function testMe()
    {

        // arrange
        $host = 'localhost';
        $user = 'user';
        $password = '1234';

        $filesArray = new ArrayObject(array(''));

        $service = new FtpService('var/tmp/');
        $service->setFTP($this->connectionMock, $this->ftpWrapperMock);
        $service->setFinder($this->finderMock);

        $this->connectionMock
            ->expects($this->once())
            ->method('open');

        $this->ftpWrapperMock
            ->expects($this->once())
            ->method('get')
            ->will($this->returnValue(true));

        $this->connectionMock
            ->expects($this->once())
            ->method('close');

        $this->finderMock
            ->expects($this->once())
            ->method('files')
            ->will($this->returnValue($this->finderMock));

        $this->finderMock
            ->expects($this->once())
            ->method('in')
            ->will($this->returnValue($filesArray));

        // act
        $file = $service->getFile('/file.zip');

        // assert
        $this->assertInstanceOf(SplFileInfo::class, $file);

    }

}

Finderclass 的模拟实例需要implement/mock 方法getIteratorgetMock 方法不接受参数,所以不要传递字符串 'Iterator'——更改代码如下:

private function getFinderMock()
{
    return $this->getMockBuilder(Finder::class)
        ->disableOriginalConstructor()
        ->getMock();
}

并在测试方法中加入Mocked期望,例如:

    $this->finderMock->expects($this->once())
        ->method('getIterator')
        ->willReturn(new \ArrayObject([$this->createMock(SplFileInfo::class)]));

希望这对您有所帮助。