我在让我的单元测试工作时遇到了一些麻烦。我正在测试一个使用工厂创建的服务的控制器。我想要实现的是用模拟服务替换工厂,这样我就可以在不使用活动数据库连接的情况下执行测试。
设置
在我的服务管理器的配置文件中,我指向一个工厂。工厂需要一个我不想在单元测试期间使用的活动数据库连接。
Namespace MyModule;
return [
'factories' => [
MyService::class => Factory\Service\MyServiceFactory::class,
],
];
注意:出于说明目的,我更改了类名和简化配置。
该服务使用我现在不会进入的映射器,因为这与情况无关。映射器在他们自己的测试用例中进行测试。服务本身也有自己的测试用例,但需要存在才能让控制器的操作起作用。
控制器操作只是从服务接收信息。
Namespace MyModule\Controller;
use MyModule\Service\MyService;
use Zend\Mvc\Controller\AbstractActionController;
class MyController extends AbstractActionController
{
/**
* @var MyService
*/
private $service;
/**
* @param MyService $service
*/
public function __construct(MyService $service)
{
$this->service = $service;
}
/**
* Provides information to the user
*/
public function infoAction()
{
return [
'result' => $this->service->findAll(),
];
}
}
注意:同样,为了便于说明,我更改了类名并简化了示例。
我试过的
在我的测试用例中,我尝试像这样覆盖所需的工厂:
/**
* @return \Prophecy\Prophecy\ObjectProphecy|MyService
*/
private function mockService()
{
$service = $this->prophesize(MyService::class);
$service->findAll()->willReturn(['foo', 'bar']);
return $service;
}
/**
* @param \Zend\ServiceManager\ServiceManager $services
*/
private function configureServiceManager(ServiceManager $services)
{
$services->setAllowOverride(true);
$services->setService(MyService::class, $this->mockService()->reveal());
$services->setAllowOverride(false);
}
乍一看,这看起来很棒,但它不起作用。它似乎只是将服务附加到服务管理器的服务列表中,而不是覆盖工厂。
更改$services->setService
为$services->setFactory
需要我建立另一个工厂。我能做的是创建一个工厂,将模拟映射器注入到服务中,但感觉不对。我正在测试控制器,而不是服务或映射器,所以我试图避免这样的复杂解决方案,以保持我的测试用例简单明了。
关于我的情况有什么选择吗?是否可以在服务管理器中使用服务覆盖工厂,还是我看错了?