Ich habe einen Controller ich für funktionale Tests erstellen möchte. Dieser Controller führt HTTP-Anforderungen an eine externe API über eine MyApiClient
Klasse aus. Ich brauche diese MyApiClient
Klasse zu verspotten, so kann ich testen, wie mein Controller für gegebene Antworten reagiert (z was wird es tun, wenn die MyApiClient
Klasse eine 500-Antwort zurückgibt).Symfony 2 Funktionstests mit verspottete Dienstleistungen
Ich habe keine Probleme mit der Erstellung einer verspotteten Version der MyApiClient
Klasse über den Standard-PHPUnit-Mockbuilder: Das Problem, das ich habe, ist mein Controller dieses Objekt für mehr als eine Anfrage zu verwenden.
Ich mache folgend zur Zeit in meinem 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;
}
}
Es scheint, als ob der Behälter, wenn die zweite Anforderung, die MyApiClient
wieder instanziiert zu verursachen gemacht wird wieder aufgebaut werden. Die MyApiClient
Klasse ausgebildet ist, einen Dienst über eine Anmerkung (den JMS DI Zusatz Bundle verwenden) und in eine Eigenschaft des Reglers über eine Anmerkung injiziert.
Ich würde jede Anfrage in einen eigenen Test teilen, um dies zu umgehen, wenn ich könnte, aber leider kann ich nicht: Ich muss eine Anfrage an den Controller über eine GET-Aktion machen und dann das Formular POST bringt zurück. Ich möchte dies aus zwei Gründen tun:
1) Das Formular verwendet CSRF-Schutz, also, wenn ich nur direkt an das Formular POST ohne den Crawler zu senden, das Formular schlägt die CSRF-Prüfung.
2) Prüfung, dass das Formular die richtige POST-Anforderung erzeugt, wenn es eingereicht wird ein Bonus.
Hat jemand irgendwelche Vorschläge, wie dies zu tun?
EDIT:
Dies kann in der folgenden Unit-Test ausgedrückt werden, die nicht auf irgendwelchen meiner Code abhängt, kann so klarer sein:
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.
}
Dieser Test schlägt fehl, auch wenn ich Rufen Sie $client->getContainer()->set($keyName, new \stdClass());
direkt vor dem zweiten Anruf an request()
Danke dafür. Ich habe diese Bibliothek nicht ausprobiert - am Ende habe ich nur eine einzige Scheinklasse, die von Symfony's DI bestimmt wird, was nicht ideal ist - aber ich werde definitiv darauf achten, dies in Zukunft zu verwenden. Dies scheint die beste Lösung für mein ursprüngliches Problem zu sein, also akzeptiere ich diese Antwort. – ChrisC