我有一个控制器,我想为其创建功能测试。该控制器通过类向外部 API 发出 HTTP 请求MyApiClient
。我需要模拟这个类,所以我可以测试我的控制器如何响应给定的响应(例如,如果类返回 500 响应MyApiClient
它将做什么)。MyApiClient
我通过标准 PHPUnit mockbuilder 创建类的模拟版本没有问题MyApiClient
:我遇到的问题是让我的控制器将此对象用于多个请求。
我目前在测试中执行以下操作:
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)配置为服务,并通过注解注入到控制器的属性中。
如果可以的话,我会将每个请求拆分为自己的测试以解决此问题,但不幸的是我做不到:我需要通过 GET 操作向控制器发出请求,然后发布它返回的表单。我想这样做有两个原因:
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.
}
此测试失败,即使我$client->getContainer()->set($keyName, new \stdClass());
在第二次调用之前立即调用request()