找到你要的答案

Q:Symfony functional tests in a sub-request oriented scenario

Q:symfony功能测试在子请求的情景

In a Symfony 2.6 / PhpUnit 4.6 environment, I am looking for a way to individually test one single request only, in a scenario where that request might invoke at a later stage (while rendering the template for example) a sub-request.

Concretely, given the following Page Controller

namespace AppBundle\Controller;

class Page extends Controller{

    public function viewAction(){
        return ...
    }

}

Which will render a Twig template containing the following line, which will invoke a sub-request to the Widget controller:

{{ render(controller('AppBundle:Widget:footerLatest')) }}

The Widget controller has it's own logic, maybe it's pulling something from the database:

namespace AppBundle\Controller;

class Widget extends Controller{

    public function footerLatestAction(){
        $foo = $this->getDoctrine()->getRepository('ModelBundle:Foo')->findBy(...);

        return [
            'foo' => $foo
        ];
    }

}

In my functional tests for the Page controller I will mock the Doctrine dependencies

namespace AppBundle\Tests\Controller;

class PageControllerTest extends \Tests\TestCase{

    public function testDetailsView(){
        $someMock = $this->getMockBuilder('ModelBundle\Entity\SomeEntity')
                ->getMock();
        $entityManagerMock = $this->getMockBuilder('Doctrine\ORM\EntityManager')
                ->setMethods(array('persist', 'flush', 'getRepository', 'clear'))
                ->disableOriginalConstructor()
                ->getMock();
        $repositoryMock = $this->getMockBuilder('ModelBundle\Repository\SomeEntityRepository')
                ->setMethods(['findOneBy', 'findBy'])
                ->disableOriginalConstructor()
                ->getMock();

        $client->getContainer()->set('doctrine.orm.default_entity_manager', $entityManagerMock);
        ...

    }

}

At this point the problem is clear: in each controller test I will make I have to take into account all the sub-requests it might invoke, and this thing snowballs to something which might look hell.

My thought is that I can safely consider that each request (either master or sub) should be treated as completely distinct things, and thus tested distinctly, ie the Page controller will have the PageControllerTest which will not invoke sub-requests (it would have nothing to do with any sub-request at all), even if it normally would. And the Widget controller would have it's own WidgetControllerTest.

So, how can I "disable/ignore" sub-requests in functional tests? Or is there a better approach?

在symfony 2.6 / PHPUnit 4.6的环境下,我在寻找一种方式单独测试一个请求,在一个场景中,请求可能调用在后期(例如渲染模板的子请求)。

具体来说,给出以下页面控制器

namespace AppBundle\Controller;

class Page extends Controller{

    public function viewAction(){
        return ...
    }

}

这将使一个小枝模板包含下面的行,这将调用子控件的小部件控制器:

{{ render(controller('AppBundle:Widget:footerLatest')) }}

控件有它自己的逻辑,可能是从数据库中拔出一些东西:

namespace AppBundle\Controller;

class Widget extends Controller{

    public function footerLatestAction(){
        $foo = $this->getDoctrine()->getRepository('ModelBundle:Foo')->findBy(...);

        return [
            'foo' => $foo
        ];
    }

}

在我的页面控制器的功能测试中,我将模拟教条依赖

namespace AppBundle\Tests\Controller;

class PageControllerTest extends \Tests\TestCase{

    public function testDetailsView(){
        $someMock = $this->getMockBuilder('ModelBundle\Entity\SomeEntity')
                ->getMock();
        $entityManagerMock = $this->getMockBuilder('Doctrine\ORM\EntityManager')
                ->setMethods(array('persist', 'flush', 'getRepository', 'clear'))
                ->disableOriginalConstructor()
                ->getMock();
        $repositoryMock = $this->getMockBuilder('ModelBundle\Repository\SomeEntityRepository')
                ->setMethods(['findOneBy', 'findBy'])
                ->disableOriginalConstructor()
                ->getMock();

        $client->getContainer()->set('doctrine.orm.default_entity_manager', $entityManagerMock);
        ...

    }

}

在这一点上的问题是明确的:在每个控制器的测试会使我必须考虑到所有的子请求可能调用,这件事情可能看起来该死的雪球。

我想,我可以把每个请求(或主或次)应被视为完全不同的东西,从而测试清楚,IE页面控制器将有pagecontrollertest不会调用子请求(它不会与任何子请求),即使它通常会。和部件的控制器都会有它自己的widgetcontrollertest。

那么,如何在功能测试中“禁用/忽略”子请求呢?或者有更好的方法?

answer1: 回答1:

If you are testing the controller then the whole logic behind the request must work. It is no longer a real unit test but a functional test. So all must work. Not just a small part of the request.

If you have a simple DB and are not using any driver specific things you can always switch to in memory SQLite DB. Edit your config_test.yml like this:

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                driver:   pdo_sqlite
                memory:   true

And prepopulate the DB with the data you need for the test.

If you can't use SQLite you can always configure a real DB with,for example, test_ prefix. It will get a bit more comlicated if you want to put this into automated build/deplozment but definitely doable.

如果您正在测试控制器,那么请求后面的整个逻辑必须工作。它不再是真正的单元测试,而是功能测试。所以一切必须工作。不只是请求的一小部分。

If you have a simple DB and are not using any driver specific things you can always switch to in memory SQLite DB. Edit your config_test.yml like this:

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                driver:   pdo_sqlite
                memory:   true

和预填充的分贝,你需要测试的数据。

如果你不能使用SQLite你总是可以配置一个真正的数据库,例如,test_前缀。它会得到一个更复杂的如果你想把它变成自动建立/ deplozment但确实是可行的。

symfony2  phpunit  twig