2016-05-03 10 views
1

Ich benutze PHPUnit ~5.2 und PHP ~7.0.0.Verwendung expectException und ein Spion in PHPUnit

Ich habe eine Klasse, die ein Repository umschließt, die Ausnahmen abfängt, einen Logger aufruft und dann die Ausnahme erneut ausliest.

public function storeDonation(Donation $donation) { 
    try { 
     $this->repository->storeDonation($donation); 
    } 
    catch (StoreDonationException $ex) { 
     $this->logger->log($this->logLevel, $ex->getMessage(), [ 'exception' => $ex ]); 
     throw $ex; 
    } 
} 

In meinen Tests habe ich ein Spion für den Logger erstellt, ich kann so sehen, welche, wo auf die Logging-Funktionen gemacht aufruft. Dieser Spion ist ein dedizierter Testdoppel, der NICHT über die PHPUnit Mocking-API erstellt wurde. Das Problem, auf das ich gestoßen bin, würde nicht auftreten, wenn ich die PHPUnit-Mocking-API verwende, aber ich frage hier nicht nach Feedback für diese Entscheidung.

Das Testverfahren, wo ich in Probleme renne hat einige Code-Setup, dann es einen Aufruf an PHPUnits hat expectException (die verwendet setExpectedException in PHPUnit 5.1 und älter sein), dann das Herstellungsverfahren nennt, und schließlich wird die Anrufe vom Spion protokollieren, um die richtigen zu bestätigen, wo sie gemacht wurden.

public function testWhenGetDonationByIdThrowException_itIsLoggedAndThrown() { 
    $logger = new LoggerSpy(); 

    $loggingRepo = new LoggingDonationRepository(
     $this->newThrowingRepository(), 
     $logger 
    ); 

    $this->expectException(GetDonationException::class); 
    $loggingRepo->getDonationById(1337); 

    $this->assertEquals(
     [ 
      [ 
       LogLevel::CRITICAL, 
       self::GET_DONATION_BY_ID_EXCEPTION_MESSAGE, 
       $this->newGetDonationException() 
      ] 
     ], 
     $logger->getLogCalls() 
    ); 
} 

Das Problem ist, dass, wenn die Ausnahme ausgelöst wird, PHPUnit es auffängt und auswertet expectException, wonach Ausführung meines Testverfahren nicht fortgesetzt. Die Behauptungen, die meinen Spion verwenden, laufen also niemals.

Ich suche nach einer Möglichkeit, dies zu lösen. Ich habe darüber nachgedacht, die Methode in eine zu teilen, die den expectException Teil hat, und eine andere, die sowohl einen Dummy Try-Catch für den Produktionscode-Aufruf als auch die Behauptungen für den Spion hat. Irgendwelche Vorschläge für bessere Ansätze?

Antwort

3

Wenn Sie eine Ausnahme auslösen, wird der gesamte folgende Code bis zu einer Fanganweisung unterbrochen. Das gilt auch für Ihre Testmethode.

PHPUnit fängt immer die Ausnahmen ab, damit es sie protokollieren kann, und indem Sie expectedException verwenden, sagen Sie ihm einfach, dass die Ausnahme behandelt werden soll, die ein wenig anders ist.

Also ja, Sie müssen Ihren eigenen try catch Block schreiben, wenn Sie nach dem Auslösen der Ausnahme weitere Prüfungen durchführen möchten. Hier ist ein Beispiel, wie Sie das tun würden:

public function testWhenGetDonationByIdThrowException_itIsLoggedAndThrown() { 
    $logger = new LoggerSpy(); 

    $loggingRepo = new LoggingDonationRepository(
     $this->newThrowingRepository(), 
     $logger 
    ); 

    try { 
     $loggingRepo->getDonationById(1337); 
    } catch (GetDonationException $e) { 
     $this->assertEquals(
      [[ 
       LogLevel::CRITICAL, 
       self::GET_DONATION_BY_ID_EXCEPTION_MESSAGE, 
       $this->newGetDonationException() 
      ]], 
      $loger->getLogCalls() 
     ); 

     return; 
    } 

    $this->fail('Expected exception wasn\'t thrown!'); 
}