功能测试 - 模拟服务不会在服务容器中持久存在

时间:2013-03-25 01:12:43

标签: php unit-testing symfony doctrine mocking

我希望有人可以对我面临的这个问题有所了解。

[问题]

我在功能单元测试中嘲笑了doctrine.orm.default_entity_manager服务。我将它注入客户端服务容器中,这样我就不必在功能测试过程中点击我的数据库。对于我刚刚涉及GET请求的测试,我能够验证我正在测试的控制器是否正在使用我的模拟服务。

但是,如果我尝试使用带有表单提交的爬网程序来执行POST请求,则我的模拟服务不会保留。在初始GET请求之后,客户端似乎只是在需要时再次注入doctrine.orm.default_entity_manager服务,而不是我在客户端服务容器中设置的模拟版本。

总之,在GET请求期间,我正在使用我的模拟服务,但在POST请求期间正在使用EntityManager5144076565ee8_546a8d27f194334ee012bfe64f629947b07e4919__CG __ \ Doctrine \ ORM \ EntityManager。 [参见下面的代码]

[问题]

有可能做我要问的事吗?我想让我的所有请求都使用我定义的模拟服务。我希望进行功能测试,但避免从数据库中写入或读取。

[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);

1 个答案:

答案 0 :(得分:2)

这里的问题是在每个请求之后(期间)启动内核:

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

所以你需要在每次请求后用你的模拟替换doctrine:

// 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');

全局使用模拟的更简单方法是覆盖config_test.yml中的学说设置

 orm:
        default_entity_manager:  Acme/MyBundle/Test/MockDoctrineEM

http://symfony.com/doc/master/reference/configuration/doctrine.html