J'ai un contrôleur pour lequel j'aimerais créer des tests fonctionnels. Ce contrôleur effectue des requêtes HTTP vers une API externe via une interface de type MyApiClient
classe. J'ai besoin de faire une simulation de cette MyApiClient
afin de pouvoir tester la façon dont mon contrôleur réagit à des réponses données (par exemple, ce qu'il fera si la classe MyApiClient
renvoie une réponse 500).
Je n'ai aucun problème à créer une version simulée de l'interface utilisateur. MyApiClient
via l'outil standard de construction de maquettes de PHPUnit : Le problème que j'ai est de faire en sorte que mon contrôleur utilise cet objet pour plus d'une requête.
Je fais actuellement ce qui suit dans mon 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;
}
}
Il semble que le conteneur soit en train d'être reconstruit lorsque la deuxième demande est faite, ce qui provoque l'apparition de l'erreur d'affichage. MyApiClient
pour être à nouveau instancié. Le site MyApiClient
est configurée pour être un service via une annotation (en utilisant le JMS DI Extra Bundle) et injectée dans une propriété du contrôleur via une annotation.
Si je le pouvais, je séparerais chaque requête dans son propre test pour contourner ce problème, mais malheureusement je ne le peux pas : je dois faire une requête au contrôleur via une action GET et ensuite POST le formulaire qu'il ramène. J'aimerais faire cela pour deux raisons :
1) Le formulaire utilise une protection CSRF, donc si j'envoie un POST directement au formulaire sans utiliser le crawler pour le soumettre, le formulaire échoue la vérification CSRF.
2) Tester que le formulaire génère la bonne requête POST lorsqu'il est soumis est un bonus.
Quelqu'un a-t-il des suggestions sur la manière de procéder ?
EDIT :
Ceci peut être exprimé dans le test unitaire suivant qui ne dépend d'aucun de mes codes, donc peut être plus clair :
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.
}
Ce test échoue, même si j'appelle $client->getContainer()->set($keyName, new \stdClass());
immédiatement avant le deuxième appel à request()