Php 如何模拟ServiceLocator ZF2?

Php 如何模拟ServiceLocator ZF2?,php,zend-framework2,phpunit,Php,Zend Framework2,Phpunit,这是一个工厂: namespace Maintenance\Factory\View\Helper; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; use Maintenance\View\Helper\SousMenuContrat; class SousMenuContratFactory implements FactoryInterface {

这是一个工厂:

namespace Maintenance\Factory\View\Helper;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Maintenance\View\Helper\SousMenuContrat;

class SousMenuContratFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
        {
            $realServiceLocator = $serviceLocator->getServiceLocator();

            $maiContratService = $realServiceLocator->get(
                'Maintenance\Service\Model\FMaiContratService'
            );   

            return new SousMenuContrat(
                $maiContratService
            );
        }
   } 
我必须写一些PHPUnit测试,我开始这样做:

public function testCreateService()
    {
        $this->mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface');
        $this->mockConnection = $this->getMock('Zend\Db\Adapter\Driver\ConnectionInterface');
        $this->mockDriver->expects($this->any())->method('checkEnvironment')->will($this->returnValue(true));
        $this->mockDriver->expects($this->any())->method('getConnection')->will($this->returnValue($this->mockConnection));
        $this->mockPlatform = $this->getMock('Zend\Db\Adapter\Platform\PlatformInterface');
        $this->mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface');
        $this->mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue($this->mockStatement));
        $this->adapter = new Adapter($this->mockDriver, $this->mockPlatform);
        $this->sql = new Sql($this->adapter);


        $mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway', array(), array(), '', false);

        $maiContratTable = $this->getMockBuilder('Maintenance\Model\BDD\FMaiContratTable')
            ->setMethods(array())
            ->setConstructorArgs(array($mockTableGateway, $this->adapter, $this->sql))
            ->getMock();


        $smMock = $this->getMockBuilder('Zend\ServiceManager\ServiceManager')
                       ->setMethods(array('get'))
                       ->getMock();

        $smMock->expects($this->at(0))
            ->method('get')
            ->with('Maintenance\Service\Model\FMaiContratService')
            ->will($this->returnValue(new FMaiContratService($maiContratTable)));

        $factory = new SousMenuContratFactory();
        $runner = $factory->createService($smMock);
    }
但我有一些问题。这告诉我:

调用未定义的方法Mock_ServiceManager_3ed93deb::getServiceLocator()

我误解了什么


谢谢

在您的工厂中,您可以调用:

$realServiceLocator = $serviceLocator->getServiceLocator();
但你定义:

$smMock->expects($this->at(0))
        ->method('get')
传递给工厂的ServiceLocator通常没有方法
getServiceLocator
,因为它已经是服务定位器。(编辑:从插件管理员那里抓起!)改用:

public function createService(ServiceLocatorInterface $serviceLocator)
{
    $maiContratService = $serviceLocator->get(
        'Maintenance\Service\Model\FMaiContratService'
    );   

    return new SousMenuContrat(
        $maiContratService
    );
}
编辑:插件工厂是另一回事,下面是测试代码:

public function testCreateService()
{
    $maiContractServiceMock = $this->getMockBuilder('Maintenance\Service\Model\FMaiContratService')
        ->disableOriginalConstructor()
        ->getMock();
    // if you do something with FMaiContratService in the constructor of SousMenuContrat,
    // mock more methods here

    $smMock = $this->getMockBuilder('Zend\ServiceManager\ServiceManager')
        ->setMethods(array('get'))
        ->getMock();
    $smMock->expects($this->at(0))
        ->method('get')
        ->with('Maintenance\Service\Model\FMaiContratService')
        ->will($this->returnValue($maiContractServiceMock));

    $hpmMock = $this->getMockBuilder('Zend\View\HelperPluginManager')
        ->setMethods(array('getServiceLocator'))
        ->getMock();
    $hpmMock->expects($this->any())
        ->method('getServiceLocator')
        ->will($this->returnValue($smMock));

    $factory = new SousMenuContratFactory();
    $runner = $factory->createService($hpmMock);
}

在这种情况下,需要模拟插件管理器,如果调用了
getServiceLocator
,则返回另一个服务定位器。德索莱

这询问了我FMaiContratService的参数,但我并没有真正调用FMaiContratService,我调用了调用FMaiContratService的工厂(通过ServiceManager)…我不确定您是否在这里,它对我来说工作正常,我没有得到错误。之所以会出现错误,是因为传递给
createService()
的模拟不知道方法
getServiceLocator()
——这很好,因为ServiceLocator接口不包含这样的方法。方法
get('Maintenance\…')
返回所需的
fmaiconstratservice
实例,不是吗?是的,但是如果我删除“$realServiceLocator=$serviceLocator->getServiceLocator()”,fmaiconstratservice由module.config.php中的工厂调用这要求我在我的web应用程序中提供FMaiContratService的参数。。。这是我工厂的工作!因此,我认为我的应用程序不再了解我的工厂。首先,创建一个
fmaiconstratservice
的模拟,不要在测试中实例化它。它的构造函数不应该被测试。您还可以使用
getMockBuilder(“…”->disableOriginalConstructor()
禁用构造函数。我想这会让你的考试更容易。这是有道理的!非常感谢!为插件创建工厂是另一回事,我只是假设您正在创建一个普通工厂!