Chr*_*isC 21 phpunit dependency-injection symfony
我有一个控制器,我想为其创建功能测试.该控制器通过MyApiClient类向外部API发出HTTP请求.我需要模拟这个MyApiClient类,所以我可以测试我的控制器如何响应给定的响应(例如,如果MyApiClient类返回500响应它将做什么).
MyApiClient通过标准的PHPUnit mockbuilder 创建类的模拟版本没有问题:我遇到的问题是让我的控制器将此对象用于多个请求.
我目前正在测试中执行以下操作:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
似乎在第二个请求发生时正在重建容器,导致MyApiClient再次实例化.所述MyApiClient类被配置为经由一个注释的服务(使用JMS DI额外包),并通过一个注解注入控制器的特性.
如果可以的话,我会将每个请求分成自己的测试来解决这个问题,但不幸的是我不能:我需要通过GET操作向控制器发出请求,然后POST它带回来的表单.我想这样做有两个原因:
1)表单使用CSRF保护,因此如果我直接POST到表单而不使用爬虫提交它,表单将无法通过CSRF检查.
2)测试表单在提交时生成正确的POST请求是奖励.
有没有人对如何做到这一点有任何建议?
编辑:
这可以在以下单元测试中表示,该测试不依赖于我的任何代码,因此可能更清楚:
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.
}
Run Code Online (Sandbox Code Playgroud)
即使我$client->getContainer()->set($keyName, new \stdClass());在第二次呼叫之前立即呼叫,此测试也会失败request()
我以为我会跳进去 Chrisc,我想你想要的是:
https://github.com/PolishSymfonyCommunity/SymfonyMockerContainer
我同意您的一般方法,在服务容器中将其配置为参数实际上不是一个好方法.整个想法是能够在单个测试运行期间动态模拟这个.
当您调用时self::createClient(),您将获得Symfony2内核的引导实例.这意味着,解析并加载所有配置.当现在发送请求时,你让系统第一次完成它的工作,对吗?
在第一个请求之后,您可能想要检查发生了什么,因此,内核处于发送请求的状态,但它仍在运行.
如果您现在运行第二个请求,则Web架构要求内核重新启动,因为它已经运行了请求.当您第二次执行请求时,将在您的代码中执行此重新引导.
如果要在发送请求之前引导内核并对其进行修改(如您所愿),则必须关闭旧内核实例并引导新内核实例.
你可以通过重新运行来做到这一点self::createClient().现在你再次必须像第一次那样应用你的模拟.
这是您的第二个示例的修改代码:
public function testAMockServiceCanBeAccessedByMultipleRequests()
{
$keyName = 'testing123';
$client = static::createClient();
$client->getContainer()->set($keyName, new \stdClass());
// Check our object is still set on the container.
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName)));
$client->request('GET', '/any/url/');
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName)));
# addded these two lines here:
$client = static::createClient();
$client->getContainer()->set($keyName, new \stdClass());
$client->request('GET', '/any/url/');
$this->assertEquals('stdClass', get_class($client->getContainer()->get($keyName)));
}
Run Code Online (Sandbox Code Playgroud)
现在您可能想要创建一个单独的方法,为您模拟新鲜实例,因此您不必复制代码...
| 归档时间: |
|
| 查看次数: |
13506 次 |
| 最近记录: |