使用 Doctrine 在 Symfony2 中测试控制器
我在 Symony2 中创建了一个非常简单的 REST 控制器,控制器操作中包含数据库插入/更新/删除.
I have created a very simple REST controller in Symony2 with Database insert/updates/deletes in the controller actions.
有没有一种很好的方法来为这些控制器操作编写单元/集成测试而不污染生产数据库?我是否必须在不同的环境中工作 - 或者框架供应商是否为此提供了建议的方法?
Is there a nice way to write unit/integration tests for these controller actions without polluting the production database? Do I have to work with different environments - or is there a proposed way from the framework vendor for this?
当前控制器示例:
public function postAction()
{
$json = $this->getRequest()->getContent();
$params = json_decode($json);
$name = $params->name;
$description = $params->description;
$sandbox = new Sandbox();
$sandbox->setName($name);
$sandbox->setDescription($description);
$em = $this->getDoctrine()->getManager();
$em->persist($sandbox);
$em->flush();
$response = new Response('/sandbox/'.$sandbox->getId());
$response->setStatusCode(201);
return $response;
}
当前测试示例:
class SandboxControllerTest extends WebTestCase
{
public function testRest()
{
$client = static::createClient();
$crawler = $client->request('POST', '/service/sandbox', array(), array(), array(), json_encode(array('name' => 'TestMe', 'description' => 'TestDesc')));
$this->assertEquals(
201, $client->getResponse()->getStatusCode()
);
}
}
推荐答案
在我看来,你绝对应该避免在测试中更改数据库.
In my opinion you should definitely avoid change database with your tests.
我最喜欢的实现方式是在测试客户端中注入实体管理器模拟.例如:
My favourite way to achieve this is inject entity manager mock inside a test client. For example:
public function testRest()
{
// create entity manager mock
$entityManagerMock = $this->getMockBuilder('DoctrineORMEntityManager')
->setMethods(array('persist', 'flush'))
->disableOriginalConstructor()
->getMock();
// now you can get some assertions if you want, eg.:
$entityManagerMock->expects($this->once())
->method('flush');
// next you need inject your mocked em into client's service container
$client = static::createClient();
$client->getContainer()->set('doctrine.orm.default_entity_manager', $entityManagerMock);
// then you just do testing as usual
$crawler = $client->request('POST', '/service/sandbox', array(), array(), array(), json_encode(array('name' => 'TestMe', 'description' => 'TestDesc')));
$this->assertEquals(
201, $client->getResponse()->getStatusCode()
);
}
您应该注意此解决方案的一件事是,您需要在每次请求之前注入您的模拟服务.这是因为客户端在每次请求之间都会重新启动内核(这意味着容器也在重建).
One thing with this solution which you should be aware is that you need inject your mocked service before each request. This is because the client reboots a kernel between each request (which means that the container is rebuild as well).
我在控制器测试中的 GET 方法是,我可以模拟实体存储库等,以便对从 db 获取的每个数据进行存根,但这需要大量工作并且不是很舒服,所以我更喜欢在这种情况下(我的意思是如果我们谈论控制器的测试)实际上从 db 获取真实数据.我所说的真实数据是指用教条固定装置创建的数据.只要我们不改变数据库,我们就可以依赖fixtures.
My GET approach in controller's tests is that I can mock entity repositories and so on in order to stub every getting data from db but it's a lot of work and it's not very comfortable, so I prefer in this case (I mean only if we speak about controller's test) actually getting real data from db. By real data I mean data created with doctrine fixtures. And as long as we don't change database we can depend on the fixtures.
但是,如果我们谈论更改 db 中的数据(POST/PUT/DELETE 方法),我总是使用模拟.如果您将使用 em mock 并对perist"和flush"方法设置适当的期望,则可以确保在没有任何数据库修改的情况下实际正确创建/更新/删除数据.
But if we are speaking about changing data inside db (POST/PUT/DELETE methods) I always use mocks. If you'll use em mock and set appropriate expectations on "perist" and "flush" methods, you can be sure that the data is correctly created/updated/deleted actually without any database's modifications.
相关文章