У меня есть контроллер, над которым я хотел бы создать функциональные тесты. Этот контроллер делает HTTP-запросы внешним API через класс MyApiClient
. Мне нужно высмеять этот класс 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;
}
}
Кажется, что контейнер перестраивается, когда выполняется второй запрос, в результате чего MyApiClient
создается снова. Класс MyApiClient
настроен как услуга посредством аннотации (с использованием JMS DI Extra Bundle) и вводится в свойство контроллера посредством аннотации.
Я бы разделил каждый запрос на свой собственный тест, чтобы обойти это, если бы мог, но, к сожалению, я не могу: мне нужно сделать запрос к контроллеру с помощью действия GET, а затем POST, который он приносит назад. Я хотел бы сделать это по двум причинам:
1) Форма использует защиту CSRF, поэтому, если я просто отправлю POST непосредственно в форму без использования искателя для ее отправки, форма не будет проверяться CSRF.
2) Проверка того, что форма генерирует правильный запрос POST, когда он отправлен, является бонусом.
Есть ли у кого-нибудь предложения о том, как это сделать?
EDIT:
Это может быть выражено в следующем unit test, который не зависит от какого-либо из моего кода, поэтому может быть яснее:
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()