Hier im Forum bekommt ihr bei euren fragen schnelle hilfe.Hier geht es rund um das Web SeitenProgrammieren.Alles rund ums Javascript,Html,Php,Css und Sql.Auf fast allen Fragen haben wir eine Antwort.
Der Soforthilfe-chat verspricht das ,was sein Name sagt. Hier sind Leute Online die sofort ihre hilfe anbieten.Seht in der OnlineListe nach und wenn einer Online ist werdet ihr auch antwort bekommen. Admine ,Moderatoren und Helfer sind unsere Spezialisten in Sachen Web Programierung
71 Unwetterwarnungen in Deutschland
Die Datenbank wurde zuletzt am 02.08.2020 17:34:28 aktualiesiert
71

Erwartete Exceptions richtig testen

Der klassische Ablauf beim Testen von Code, der eine Exception werfen soll, ist der Folgende (PHPUnit):

/**  * @expectedException InvalidArgumentException  */ public function testException() {    throw new InvalidArgumentException(); } 

Problem dabei: Wir haben nicht spezifiziert, an welcher Stelle die Exception geworfen werden soll. Außerdem können wir nicht prüfen, ob die geworfene Exception genau die erwartete oder nur igendeine war.

Jetzt lässt sich das noch aufbohren:

/**  * @expectedException        InvalidArgumentException  * @expectedExceptionMessage Right Message  */ public function testExceptionHasRightMessage() {     throw new InvalidArgumentException('Right Message'); } 

Auch damit werde ich nicht glücklich. Wenn ich jetzt z.B. mehrere Exceptions in einem Test prüfen möchte (guter Stil hin oder her) stößt man an die Grenzen diesen Ansatzes.

Etwas feingranularer ist das Handling mit der nachfolgend vorstellten Methode setExpectedException.

Alternative Methode

public function testExceptionHasRightMessage() {     $this->setExpectedException(       'InvalidArgumentException', 'Right Message'     ); 	     throw new InvalidArgumentException('Right Message'); } 

Macht letztlich einen entscheidenden Unterschied verglichen mit der Variante per Annotation: Ich kann den Zeitpunkt selbst bestimmen, ab dem ich eine Exception erwarte. Die Annotation greift direkt ab der ersten Zeile der Methode, in der ich vielleicht noch garkeine Exception haben möchte.

Weils so schön simpel ist: Das macht setExpectedException under the hood:

public function setExpectedException($exceptionName, $exceptionMessage = '', $exceptionCode = 0) {     if ($exceptionName == 'Exception') { 	throw new InvalidArgumentException( 	  'You must not expect the generic exception class.'   	);     }      $this->expectedException        = $exceptionName;     $this->expectedExceptionMessage = $exceptionMessage;     $this->expectedExceptionCode    = $exceptionCode;     $this->expectedExceptionTrace   = debug_backtrace(); } 

… und wenn dann eine Exception fliegt, prüft das PHP Unit folgendermaßen ab:

try { 	$testResult = $method->invokeArgs( 	      $this, array_merge($this->data, $this->dependencyInput) 	); }  catch (Exception $e) { 	if (!$e instanceof PHPUnit_Framework_IncompleteTest && 		!$e instanceof PHPUnit_Framework_SkippedTest && 		is_string($this->expectedException) && 		$e instanceof $this->expectedException) { 		if (is_string($this->expectedExceptionMessage) && 			!empty($this->expectedExceptionMessage)) { 			$this->assertContains( 			  $this->expectedExceptionMessage, 			  $e->getMessage() 			); 		}        // ... } 

Volle Kontrolle!

Auch wenn das Testen mehrerer Exceptions in einer Methode durchaus umstritten ist, gibt es nun noch ein weiteres, gern genutztes Pattern, das eben dies ermöglicht:

try {     code();     $this->fail("No Exception was thrown"); } catch (InvalidArgumentException $ex) {     $this->assertEquals($ex->getMessage(), "Expected Exception-Text", "Wrong exceptiontext..."); } catch (Exception $ex) {     $this->fail("Wrong Exception was thrown"); } 

Muss natürlich für maximalen Komfort noch ausgebaut werden, ihr versteht worauf ich hinauswill.

Um das etwas komfortabler und wiederholungsfreier zu gestalten, hat dieser Herr eine Erweiterung zu PHPUnit geschrieben, womit uns seine Methode assertThrowsException die Arbeit abnimmt und den zu testenden Code in einer anonymen Funktion kapselt. Fühlt sich für mich am sympathischsten an.

<?php public function testSomeImportantMethod() {     $someClass = new SomeClass();      $this->assertThrowsException('InvalidArgumentException', function () use($someClass) {             $someClass->someMethod();         }     ); } 

Update: Danke an Thomas für eine Richtigstellung, habe den Artikel entsprechend angepasst.