Symfony 2-Funktionstests mit verspotteten Diensten

Ich habe einen Controller, für den ich Funktionstests erstellen möchte. Dieser Controller sendet HTTP-Anforderungen an eine externe API über aMyApiClient Klasse. Ich muss das verspottenMyApiClient Klasse, damit ich testen kann, wie mein Controller auf bestimmte Antworten reagiert (z. B. was wird er tun, wenn dieMyApiClient Klasse gibt eine Antwort von 500 zurück).

Ich habe keine Probleme damit, eine verspottete Version der zu erstellenMyApiClient Klasse über den Standard-Mockbuilder von PHPUnit: Das Problem ist, dass mein Controller dieses Objekt für mehr als eine Anforderung verwendet.

In meinem Test mache ich derzeit Folgendes:

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 sieht so aus, als würde der Container gerade neu aufgebaut, wenn die zweite Anfrage gestellt wirdMyApiClient wieder instanziiert werden. DasMyApiClient Klasse ist so konfiguriert, dass sie über eine Annotation (mithilfe des JMS DI-Zusatzpakets) ein Service ist und über eine Annotation in eine Eigenschaft des Controllers eingefügt wird.

Ich würde jede Anforderung in einen eigenen Test aufteilen, um dies zu umgehen, wenn ich könnte, aber leider kann ich nicht: Ich muss eine Anforderung über eine GET-Aktion an den Controller senden und dann das zurückgebrachte Formular POSTEN. Ich möchte dies aus zwei Gründen tun:

1) Das Formular verwendet CSRF-Schutz. Wenn ich also direkt ein POST an das Formular durchführe, ohne den Crawler zum Senden zu verwenden, besteht das Formular die CSRF-Prüfung nicht.

2) Es ist ein Bonus, zu testen, ob das Formular bei der Übermittlung die richtige POST-Anforderung generiert.

Hat jemand irgendwelche Vorschläge, wie man das macht?

BEARBEITEN:

Dies kann im folgenden Komponententest ausgedrückt werden, der von keinem meiner Codes abhängt.

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 anrufe$client->getContainer()->set($keyName, new \stdClass()); unmittelbar vor dem zweiten Anruf anrequest()

Antworten auf die Frage(6)

Ihre Antwort auf die Frage