Ho un controller per cui vorrei creare test funzionali. Questo controller esegue richieste HTTP a un'API esterna tramite una classe MyApiClient
. Ho bisogno di prendere in giro questa classe MyApiClient
, in modo da poter verificare come il mio controller risponde per le risposte date (ad esempio cosa farà se la classe MyApiClient
restituisce una risposta 500).Test funzionali di symfony 2 con servizi di simulazione
Non ho problemi a creare una versione derisoria della classe MyApiClient
tramite lo standard PHPUnit mockbuilder: Il problema che sto riscontrando è che il mio controller utilizza questo oggetto per più di una richiesta.
Attualmente sto facendo il seguente nel mio 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;
}
}
Sembra come se il contenitore è in fase di ricostruzione quando la seconda richiesta è fatta, causando la MyApiClient
creare un'istanza di nuovo. La classe MyApiClient
è configurata per essere un servizio tramite un'annotazione (utilizzando il pacchetto aggiuntivo JMS DI) e immessa in una proprietà del controllore tramite un'annotazione.
Mi piacerebbe dividere ogni richiesta nel suo test per risolvere il problema se possibile, ma sfortunatamente non posso: ho bisogno di fare una richiesta al controller tramite un'azione GET e poi POST il modulo porta indietro. Mi piacerebbe farlo per due motivi:
1) Il modulo utilizza la protezione CSRF, quindi se invio POST direttamente al modulo senza utilizzare il crawler per inviarlo, il modulo non supera il controllo CSRF.
2) Verificare che il modulo generi la richiesta POST corretta quando viene inviato è un bonus.
Qualcuno ha qualche suggerimento su come farlo?
EDIT:
Questo può essere espressa nella seguente test di unità che non dipende da alcuna del mio codice, quindi potrebbe essere più chiaro:
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.
}
Questo test ha esito negativo, anche se chiama $client->getContainer()->set($keyName, new \stdClass());
immediatamente prima della seconda chiamata a request()
Grazie per questo. Non ho provato questa libreria - ho finito con l'avere una sola classe di simulazione che è determinata dal DI di Symfony, che non è l'ideale - ma sicuramente cercherò di usarlo in futuro. Questo sembra essere il più adatto al mio problema originale, quindi accetto questa risposta. – ChrisC