Testen der Rückgabewert eines Verfahrens, das einen Fehler mit PHPUnit triggert
-
22-07-2019 - |
Frage
Diese Frage ist spezifisch für mit PHPUnit.
PHPUnit wandelt automatisch PHP-Fehler zu Ausnahmen. Gibt es eine Möglichkeit, den Rückgabewert einer Methode zu testen, die ein PHP-Fehler (entweder eingebaut in Fehler oder Benutzer erzeugt Fehler über trigger_error )?
Beispiel-Code zu testen:
function load_file ($file)
{
if (! file_exists($file)) {
trigger_error("file {$file} does not exist", E_USER_WARNING);
return false;
}
return file_get_contents($file);
}
Dies ist die Art von Test, den ich schreiben will:
public function testLoadFile ()
{
$this->assertFalse(load_file('/some/non-existent/file'));
}
Das Problem, das ich habe ist, dass der ausgelöste Fehler meines Unit-Test (wie es sein soll) scheitern verursacht. Aber wenn ich versuche, es zu fangen, oder eine erwartete Ausnahme, dass jeder Code festgelegt, nachdem der Fehler ausgelöst wird nie ausgeführt, so habe ich keine Möglichkeit, den Rückgabewert der Methode zu testen.
Dieses Beispiel funktioniert nicht:
public function testLoadFile ()
{
$this->setExpectedException('Exception');
$result = load_file('/some/non-existent/file');
// code after this point never gets executed
$this->assertFalse($result);
}
Irgendwelche Ideen, wie ich das erreichen kann?
Lösung
Es gibt keine Möglichkeit, dies innerhalb einer Einheit Test zu tun. Es ist möglich, wenn Sie den Rückgabewert testen zu brechen, und die Mitteilung in zwei verschiedene Tests.
Wie PHPUnit Fehlerhandler fängt PHP-Fehler dar und wandelt sie in Ausnahmen - die definitionsProgrammAusführung stoppt. Die Funktion, die Sie testen werden wieder überhaupt nicht. Sie können jedoch vorübergehend die Umwandlung von Fehlern in Ausnahmen deaktivieren, selbst zur Laufzeit.
Dies ist wahrscheinlich einfacher, mit einem Beispiel, so, hier ist es, was die beiden Tests sollen wie folgt aussehen:
public function testLoadFileTriggersErrorWhenFileNotFound()
{
$this->setExpectedException('PHPUnit_Framework_Error_Warning'); // Or whichever exception it is
$result = load_file('/some/non-existent/file');
}
public function testLoadFileRetunsFalseWhenFileNotFound()
{
PHPUnit_Framework_Error_Warning::$enabled = FALSE;
$result = load_file('/some/non-existent/file');
$this->assertFalse($result);
}
Dies hat auch den zusätzlichen Bonus Ihrer Tests klarer, sauberer und selbstdokumentiere zu machen.
Re: Kommentar: Das ist eine große Frage, und ich hatte keine Ahnung, bis ich ein paar Tests lief. Es sieht aus, als ob es wird nicht die Standard / ursprünglichen Wert wiederherzustellen, zumindest von PHPUnit 3.3.17 (die aktuelle stabile Version jetzt).
Also, ich würde die oben tatsächlich ändern, wie so aussehen:
public function testLoadFileRetunsFalseWhenFileNotFound()
{
$warningEnabledOrig = PHPUnit_Framework_Error_Warning::$enabled;
PHPUnit_Framework_Error_Warning::$enabled = false;
$result = load_file('/some/non-existent/file');
$this->assertFalse($result);
PHPUnit_Framework_Error_Warning::$enabled = $warningEnabledOrig;
}
Re: Zweite Bemerkung:
Das ist nicht ganz richtig. Ich bin auf PHPUnit Fehlerbehandlung suchen, und es funktioniert wie folgt:
- Wenn es eine
E_WARNING
, VerwendungPHPUnit_Framework_Error_Warning
als Ausnahmeklasse. - Wenn es ein
E_NOTICE
oderE_STRICT
Fehler ist, verwenden SiePHPUnit_Framework_Error_Notice
- Else, verwenden
PHPUnit_Framework_Error
als Ausnahmeklasse.
Also, ja, Fehler der E_USER_*
nicht in PHPUnit * _Warning eingeschaltet sind oder * _Notice Klasse, sind sie immer noch in eine generische PHPUnit_Framework_Error
Ausnahme umgewandelt.
Weitere Gedanken
Während es genau abhängt, wie die Funktion verwendet wird, würde ich wahrscheinlich wechseln eine tatsächliche Ausnahme statt Auslösen eines Fehlers zu werfen, wenn es nach mir ginge. Ja, das würde den Ablauf des Verfahrens Logik ändern, und den Code, der die Methode verwendet ... jetzt die Ausführung stoppt nicht, wenn eine Datei nicht lesen kann. Aber das ist an Ihnen zu entscheiden, ob die angeforderte Datei nicht existiert, ist wirklich außergewöhnliche Verhalten. Ich neige dazu, Ausnahmen Art und Weise mehr als Fehler / Warnungen / Hinweise zu verwenden, da sie einfacher zu handhaben sind, zu testen und arbeiten in Ihre Anwendung fließen. Ich in der Regel die Hinweise für Dinge wie abgeschrieben Methodenaufrufe reservieren, etc.
Andere Tipps
eine phpunit.xml
Konfigurationsdatei verwenden und die Benachrichtigung / Warnung / Fehler Ausnahme Konvertierung deaktivieren. Mehr Details im Handbuch . Es ist im Grunde so etwas wie folgt aus:
<phpunit convertErrorsToExceptions="false"
convertNoticesToExceptions="false"
convertWarningsToExceptions="false">
</phpunit>
Statt eines generischen "Exception
" erwartet, was eine "PHPUnit_Framework_Error
" erwartet?
So etwas wie dies tun könnte:
/**
* @expectedException PHPUnit_Framework_Error
*/
public function testFailingInclude()
{
include 'not_existing_file.php';
}
Which, nehme ich an, vielleicht auch wie folgt geschrieben werden:
public function testLoadFile ()
{
$this->setExpectedException('PHPUnit_Framework_Error');
$result = load_file('/some/non-existent/file');
// code after this point never gets executed
$this->assertFalse($result);
}
Weitere Informationen finden Sie unter Testen von PHP-Fehler
Vor allem heißt es (Zitat):
PHPUnit_Framework_Error_Notice
undPHPUnit_Framework_Error_Warning
vertreten PHP Hinweise und Warnungen sind.
Mit Blick auf die /usr/share/php/PHPUnit/TextUI/TestRunner.php Datei, die ich auf meinem System, ich sehe das (Linie 198 und folgende) :
if (!$arguments['convertNoticesToExceptions']) {
PHPUnit_Framework_Error_Notice::$enabled = FALSE;
}
if (!$arguments['convertWarningsToExceptions']) {
PHPUnit_Framework_Error_Warning::$enabled = FALSE;
}
Also vielleicht werden Sie irgendeine Art von Parametern übergeben müssen, um dieses Verhalten zu aktivieren? Aber es scheint standardmäßig ...
aktiviert werdenEigentlich gibt es eine Möglichkeit, sowohl den Rückgabewert und die Ausnahme geworfen zu testen (in diesem Fall ein Fehler von PHPUnit umgewandelt).
Sie müssen nur Folgendes tun:
public function testLoadFileTriggersErrorWhenFileNotFound()
{
$this->assertFalse(@load_file('/some/non-existent/file'));
$this->setExpectedException('PHPUnit_Framework_Error_Warning'); // Or whichever exception it is
load_file('/some/non-existent/file');
}
Beachten Sie, dass für den Rückgabewert zu testen, haben die Fehlerunterdrückungs Operator auf den Funktionsaufruf zu verwenden (die @
vor dem Funktionsnamen). Auf diese Weise wird keine Ausnahme ausgelöst werden, und die Ausführung wird fortgesetzt. Sie dann die erwartete Ausnahme wie üblich gesetzt haben, um den Fehler zu testen.
Was Sie nicht tun können, ist Test mehrere Ausnahmen innerhalb einer Unit-Test.