功能测试 - Mock服务不会保留在服务容器中 [英] Functional Test - Mock service does not persist in service container
问题描述
[问题]
我在我的功能单元测试中嘲笑了doctrine.orm.default_entity_manager服务。我将这个注入到客户端服务容器中,这样我在功能测试过程中就不必打DB了。对于我的测试,只需要一个GET请求,我可以验证我正在测试的控制器是否使用我的嘲笑服务。
但是,如果我尝试做一个POST通过使用履带式提交表单提交请求,我的嘲笑服务不会持续。在初始GET请求之后,客户端似乎只是根据需要再次注入doctrine.orm.default_entity_manager服务,而不是我在客户端服务容器中设置的嘲笑版本。总而言之,在GET请求期间,我的嘲笑服务正在被使用,但在POST请求期间,正在使用EntityManager5144076565ee8_546a8d27f194334ee012bfe64f629947b07e4919__CG__\Doctrine\ORM\EntityManager。
[查看下面的代码下载]
[QUESTION]
可以做我所要求的吗?我想让我的所有请求都使用我定义的嘲笑服务。我想要一个功能测试,但是避免从数据库中写入或读取。
[样本代码]
// Mocks
$ entityRepository = $ this
- > getMockBuilder('Doctrine\ORM\EntityRepository')
- > setMethods ('findby')) - > disableOriginalConstructor()
- > getMock();
$ entityRepository-> expects($ this-> any()) - >方法('findBy')
- >将($ this-> returnValue ()));
$ em = $ this-> getMockBuilder('Doctrine\ORM\EntityManager')
- > setMethods(
array('getRepository','getClassMetadata' ,'flush',
'persist')) - > disableOriginalConstructor()
- > getMock();
$ em-> expects($ this-> any()) - >方法('flush')
- >将($ this-> returnValue(FALSE ));
$ em-> expects($ this-> any()) - >方法('persist')
- >将($ this-> returnValue(FALSE ));
$ em-> expects($ this-> any()) - >方法('getRepository')
- >将($ this-> returnValue entityRepository));
$ em-> expects($ this-> any()) - >方法('getClassMetadata')
- >将($ this-> returnValue ClassMetadata( 测试)));
//创建测试客户端。
$ client = static :: createClient();
//将实体模拟进入服务容器。
$ client-> getContainer()
- > set('doctrine.orm.default_entity_manager',$ em,'container');
//定义请求
$ crawler = $ client-> request('GET','/ locations / types / add');
//验证一些东西
$ form = $ crawler-> selectButton('submit') - > form();
$ form ['location_type [title]'] =TEST TITLE;
$ form ['location_type [description]'] =TEST DESCP;
$ crawler = $ client-> submit($ form);
这里的问题是内核启动后期间)每个请求:
保护功能doRequest($ request)
{
//避免关闭内核,如果没有执行请求
// WebTestCase :: createClient()启动内核但是不处理请求
如果($ this-> hasPerformedRequest){
$ this - >内核级>关闭();
} else {
$ this-> hasPerformedRequest = true;
}
if($ this-> profiler){
$ this-> profiler = false;
$ this-> kernel-> boot();
$ this-> kernel-> getContainer() - > get('profiler') - > enable();
}
https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Client.php
所以你需要在每个请求后用你的模拟替换原则:
//将实体模拟器插入服务容器。
$ client-> getContainer()
- > set('doctrine.orm.default_entity_manager',$ em,'container');
//定义请求
$ crawler = $ client-> request('GET','/ locations / types / add');
//将实体模拟进入服务容器。
$ client-> getContainer()
- > set('doctrine.orm.default_entity_manager',$ em,'container');
全局使用你的模拟的更简单的方法是覆盖config_test.yml中的原则设置
orm:
pre>
default_entity_manager:Acme / MyBundle / Test / MockDoctrineEM
http:/ /symfony.com/doc/master/reference/configuration/doctrine.html
I am hoping someone can shed some light on this issue I am facing.
[PROBLEM]
I have mocked out doctrine.orm.default_entity_manager service in my functional unit test. I inject this into the client service container so that I do not have to hit my DB during the course of my functional test. For my test that just involve a GET request I am able to verify that the controller I am testing is using my mocked service.
However, if I attempt to do a POST request by using the crawler with a form submission my mocked service does not persist. After the initial GET request the client seems to just inject doctrine.orm.default_entity_manager service again as it needs it and not my mocked version that I set in the clients service container.
In summary, during the GET request my mocked service is being used, but during the POST request EntityManager5144076565ee8_546a8d27f194334ee012bfe64f629947b07e4919__CG__\Doctrine\ORM\EntityManager is being used. [SEE CODE SNIPPET BELOW]
[QUESTION]
Is it possible to do what I am asking? I would like to have ALL my requests use the mocked service I defined. I want to have a functional test but avoid writing or reading from the database.
[SAMPLE CODE]
// Mocks $entityRepository = $this ->getMockBuilder('Doctrine\ORM\EntityRepository') ->setMethods(array('findby'))->disableOriginalConstructor() ->getMock(); $entityRepository->expects($this->any())->method('findBy') ->will($this->returnValue(array())); $em = $this->getMockBuilder('Doctrine\ORM\EntityManager') ->setMethods( array('getRepository', 'getClassMetadata', 'flush', 'persist'))->disableOriginalConstructor() ->getMock(); $em->expects($this->any())->method('flush') ->will($this->returnValue(FALSE)); $em->expects($this->any())->method('persist') ->will($this->returnValue(FALSE)); $em->expects($this->any())->method('getRepository') ->will($this->returnValue($entityRepository)); $em->expects($this->any())->method('getClassMetadata') ->will($this->returnValue(new ClassMetadata("test"))); // Create test client. $client = static::createClient(); // Inject entity mock into service container. $client->getContainer() ->set('doctrine.orm.default_entity_manager', $em, 'container'); // Define request $crawler = $client->request('GET', '/locations/types/add'); // Verify a few things $form = $crawler->selectButton('submit')->form(); $form['location_type[title]'] = "TEST TITLE"; $form['location_type[description]'] = "TEST DESCP"; $crawler = $client->submit($form);
解决方案The issue here is that the kernel is booted after (during) every request:
protected function doRequest($request) { // avoid shutting down the Kernel if no request has been performed yet // WebTestCase::createClient() boots the Kernel but do not handle a request if ($this->hasPerformedRequest) { $this->kernel->shutdown(); } else { $this->hasPerformedRequest = true; } if ($this->profiler) { $this->profiler = false; $this->kernel->boot(); $this->kernel->getContainer()->get('profiler')->enable(); }
https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Client.php
So you need to replace doctrine with your mock after each request:
// Inject entity mock into service container. $client->getContainer() ->set('doctrine.orm.default_entity_manager', $em, 'container'); // Define request $crawler = $client->request('GET', '/locations/types/add'); // Inject entity mock into service container. $client->getContainer() ->set('doctrine.orm.default_entity_manager', $em, 'container');
An easier way to use your mock globally would be to override the doctrine settings in config_test.yml
orm: default_entity_manager: Acme/MyBundle/Test/MockDoctrineEM
http://symfony.com/doc/master/reference/configuration/doctrine.html
这篇关于功能测试 - Mock服务不会保留在服务容器中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!