Mam kontroler, dla którego chcę utworzyć testy funkcjonalne. Ten kontroler wysyła żądania HTTP do zewnętrznego interfejsu API za pośrednictwem klasy MyApiClient
. Muszę wyśmiewać tę klasę MyApiClient
, więc mogę przetestować, w jaki sposób mój kontroler odpowiada na podane odpowiedzi (np. Co zrobi, jeśli klasa MyApiClient
zwróci odpowiedź 500).Testy funkcjonalne Symfony 2 z wyśmiewanymi usługami
Nie mam problemów z tworzeniem wyśmiewanej wersji klasy MyApiClient
za pośrednictwem standardowego mockbuildera PHPUnit: Problem, który mam, polega na tym, że mój kontroler używa tego obiektu do więcej niż jednego żądania.
Jestem obecnie w następujący sposób w moim teście:
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;
}
}
Wydaje się, że pojemnik jest przebudowywany, gdy drugi wniosek został złożony, powodując MyApiClient
do ponownego wystąpienia. Klasa MyApiClient
jest skonfigurowana jako usługa za pomocą adnotacji (przy użyciu pakietu JMS DI Extra) i wstrzyknięta do właściwości kontrolera za pomocą adnotacji.
Chciałbym podzielić każde żądanie na własny test, aby obejść ten problem, gdybym mógł, ale niestety nie mogę: muszę wysłać żądanie do kontrolera za pomocą akcji GET, a następnie POST formularza przynieść z powrotem. Chciałbym to zrobić z dwóch powodów:
1) Formularz korzysta z ochrony CSRF, więc jeśli po prostu POST bezpośrednio do formularza bez korzystania z przeszukiwacza, aby przesłać go, formularz nie przechodzi kontroli CSRF.
2) Testowanie, że formularz generuje prawidłowe żądanie POST po jego przesłaniu, jest bonusem.
Czy ktoś ma jakieś sugestie, jak to zrobić?
EDIT:
To może być wyrażona w następujący testów jednostkowych, które nie zależy od żadnego z mojego kodu, więc może być wyraźniejszy:
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.
}
Ten test nie powiedzie się, nawet jeśli zadzwoń pod numer $client->getContainer()->set($keyName, new \stdClass());
bezpośrednio przed drugim połączeniem do request()
Dzięki za to. Nie próbowałem tej biblioteki - skończyło się na tym, że miałem tylko jedną próbną klasę, która jest określona przez DI DI Symfony, która nie jest idealna - ale na pewno przyjrzę się używaniu tego w przyszłości. To wydaje się najlepiej pasować do mojego pierwotnego problemu, więc akceptuję tę odpowiedź. – ChrisC