具有模拟服务的Symfony 2功能测试 [英] Symfony 2 functional tests with mocked services

查看:74
本文介绍了具有模拟服务的Symfony 2功能测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个控制器,我想为其创建功能测试.该控制器通过MyApiClient类向外部API发出HTTP请求.我需要模拟该MyApiClient类,以便测试控制器对给定响应的响应方式(例如,如果MyApiClient类返回500响应,它将如何处理).

I have a controller I'd like to create functional tests for. This controller makes HTTP requests to an external API via a MyApiClient class. I need to mock out this MyApiClient class, so I can test how my controller responds for given responses (e.g. what will it do if the MyApiClient class returns a 500 response).

我没有通过标准PHPUnit模拟构建器创建MyApiClient类的模拟版本的问题:我遇到的问题是让我的控制器将这个对象用于多个请求.

I have no problems creating a mocked version of the MyApiClient class via the standard PHPUnit mockbuilder: The problem I'm having is getting my controller to use this object for more than one request.

我目前正在测试中进行以下操作:

I'm currently doing the following in my test:

class ApplicationControllerTest extends WebTestCase
{

    public function testSomething()
    {
        $client = static::createClient();

        $apiClient = $this->getMockMyApiClient();

        $client->getContainer()->set('myapiclient', $apiClient);

        $client->request('GET', '/my/url/here');

        // Some assertions: Mocked API client returns 500 as expected.

        $client->request('GET', '/my/url/here');

        // Some assertions: Mocked API client is not used: Actual MyApiClient instance is being used instead.
    }

    protected function getMockMyApiClient()
    {
        $client = $this->getMockBuilder('Namespace\Of\MyApiClient')
            ->setMethods(array('doSomething'))
            ->getMock();

        $client->expects($this->any())
            ->method('doSomething')
            ->will($this->returnValue(500));

        return $apiClient;
    }
}

当发出第二个请求时,似乎正在重建容器,从而导致再次实例化MyApiClient. MyApiClient类被配置为通过注释(使用JMS DI Extra Bundle)作为服务,并通过注释注入到控制器的属性中.

It seems as though the container is being rebuilt when the second request is made, causing the MyApiClient to be instantiated again. The MyApiClient class is configured to be a service via an annotation (using the JMS DI Extra Bundle) and injected into a property of the controller via an annotation.

如果可以的话,我将每个请求拆分为自己的测试,以解决此问题,但是不幸的是,我做不到:我需要通过GET操作向控制器提出请求,然后发布它带来的表单背部.我要这样做有两个原因:

I'd split each request out into its own test to work around doing this if I could, but unfortunately I can't: I need to make a request to the controller via a GET action and then POST the form it brings back. I'd like to do this for two reasons:

1)表单使用CSRF保护,因此,如果我只是直接过帐到表单而没有使用搜寻器提交表单,则表单将无法通过CSRF检查.

1) The form uses CSRF protection, so if I just POST directly to the form without using the crawler to submit it, the form fails the CSRF check.

2)测试表单在提交时会生成正确的POST请求是一个奖励.

2) Testing that the form generates the correct POST request when it is submitted is a bonus.

有人对此有任何建议吗?

Does anyone have any suggestions on how to do this?

这可以在不依赖于我的任何代码的以下单元测试中表达,因此可能更清楚:

This can be expressed in the following unit test that does not depend on any of my code, so may be clearer:

public function testAMockServiceCanBeAccessedByMultipleRequests()
{
    $client = static::createClient();

    // Set the container to contain an instance of stdClass at key 'testing123'.
    $keyName = 'testing123';
    $client->getContainer()->set($keyName, new \stdClass());

    // Check our object is still set on the container.
    $this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName))); // Passes.

    $client->request('GET', '/any/url/');

    $this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName))); // Passes.

    $client->request('GET', '/any/url/');

    $this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName))); // Fails.
}

即使我在第二次致电request()

推荐答案

我认为我会跳到这里.克里斯克,我想您想要的是这里:

I thought I'd jump in here. Chrisc, I think what you want is here:

https://github.com/PolishSymfonyCommunity/SymfonyMockerContainer

我同意您的一般方法,在服务容器中将其配置为参数确实不是一个好方法.整个想法是能够在单独的测试运行过程中动态模拟这一点.

I agree with your general approach, configuring this in the service container as a parameter is really not a good approach. The whole idea is to be able to mock this dynamically during individual test runs.

这篇关于具有模拟服务的Symfony 2功能测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆