wake-up-neo.com

PHPUnit behaupten, dass eine Ausnahme ausgelöst wurde?

Weiß jemand, ob es eine assert oder etwas Ähnliches gibt, mit dem getestet werden kann, ob im getesteten Code eine Ausnahme ausgelöst wurde?

248
Felipe Almeida
<?php
require_once 'PHPUnit/Framework.php';

class ExceptionTest extends PHPUnit_Framework_TestCase
{
    public function testException()
    {
        $this->expectException(InvalidArgumentException::class);
        // or for PHPUnit < 5.2
        // $this->setExpectedException(InvalidArgumentException::class);

        //...and then add your test code that generates the exception 
        exampleMethod($anInvalidArgument);
    }
}

ExpectException () PHPUnit-Dokumentation

PHPUnit-Artikel des Autors enthält detaillierte Erklärungen zu bewährten Vorgehensweisen für das Testen von Ausnahmen.

422
Frank Farmer

Sie können auch eine Annotation docblock verwenden:

class ExceptionTest extends PHPUnit_Framework_TestCase
{
    /**
     * @expectedException InvalidArgumentException
     */
    public function testException()
    {
        ...
    }
}

Für PHP 5.5+ (insbesondere mit Namespace-Code) nutze ich jetzt lieber ::class

108
David Harkness

Wenn Sie mit PHP 5.5+ arbeiten, können Sie ::class resolution verwenden, um den Namen der Klasse mit expectExceptionsetExpectedException zu erhalten. Dies bietet mehrere Vorteile:

  • Der Name wird mit seinem Namespace (falls vorhanden) vollständig qualifiziert.
  • Es löst sich in eine string auf, so dass es mit jeder Version von PHPUnit funktioniert.
  • Sie erhalten Code-Vervollständigung in Ihrer IDE.
  • Der Compiler PHP gibt einen Fehler aus, wenn Sie den Klassennamen falsch eingeben.

Beispiel:

namespace \My\Cool\Package;

class AuthTest extends \PHPUnit_Framework_TestCase
{
    public function testLoginFailsForWrongPassword()
    {
        $this->expectException(WrongPasswordException::class);
        Auth::login('Bob', 'wrong');
    }
}

PHP kompiliert

WrongPasswordException::class

in

"\My\Cool\Package\WrongPasswordException"

ohne dass PHPUnit der klügere ist.

_/Note: PHPUnit 5.2 hatexpectException als Ersatz für setExpectedException eingeführt.

31
David Harkness

Der folgende Code testet die Ausnahmemeldung und den Ausnahmecode. 

Wichtig: Es schlägt fehl, wenn die erwartete Ausnahme nicht ebenfalls geworfen wird.

try{
    $test->methodWhichWillThrowException();//if this method not throw exception it must be fail too.
    $this->fail("Expected exception 1162011 not thrown");
}catch(MySpecificException $e){ //Not catching a generic Exception or the fail function is also catched
    $this->assertEquals(1162011, $e->getCode());
    $this->assertEquals("Exception Message", $e->getMessage());
}
27
Farid Movsumov

Sie können assertException extension verwenden, um während einer Testausführung mehrere Ausnahmen geltend zu machen.

Fügen Sie die Methode in Ihr Testfeld ein und verwenden Sie:

public function testSomething()
{
    $test = function() {
        // some code that has to throw an exception
    };
    $this->assertException( $test, 'InvalidArgumentException', 100, 'expected message' );
}

Ich habe auch eine Eigenschaft für Liebhaber von Nice-Code gemacht ..

23
hejdav

Ein alternativer Weg kann der folgende sein:

$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Expected Exception Message');

Stellen Sie sicher, dass Ihre Testklasse \PHPUnit_Framework_TestCase reicht.

10
public function testException() {
    try {
        $this->methodThatThrowsException();
        $this->fail("Expected Exception has not been raised.");
    } catch (Exception $ex) {
        $this->assertEquals($ex->getMessage(), "Exception message");
    }

}
9
ab_wanyama

Umfassende Lösung

PHPUnits aktuelles " Best Practices " für Ausnahmetests scheinen .. glanzlos ( docs ).

Da ich stimme überhaupt nicht zu mit der aktuellen expectException-Implementierung, habe ich eine Eigenschaft für meine Testfälle erstellt. Es ist nur 50 Zeilen .

  • Unterstützt mehrere Ausnahmen pro Test
  • Unterstützt Assertions, die aufgerufen werden, nachdem die Ausnahme ausgelöst wurde
  • Robuste und klare Anwendungsbeispiele
  • Standard assert Syntax
  • Unterstützt Zusicherungen für mehr als nur Nachrichten, Code und Klasse
  • Unterstützt inverse Assertion, assertNotThrows

Bibliothek

Ich habe das Merkmal AssertThrows für Github und packagist veröffentlicht, damit es mit dem Composer installiert werden kann.

Einfaches Beispiel

Nur um den Geist hinter der Syntax zu veranschaulichen:

<?php

// Using simple callback
$this->assertThrows(MyException::class, [$obj, 'doSomethingBad']);

// Using anonymous function
$this->assertThrows(MyException::class, function() use ($obj) {
    $obj->doSomethingBad();
});

Ziemlich ordentlich?


Beispiel für eine vollständige Verwendung

Nachfolgend finden Sie ein ausführlicheres Anwendungsbeispiel:

<?php

declare(strict_types=1);

use Jchook\AssertThrows\AssertThrows;
use PHPUnit\Framework\TestCase;

// These are just for illustration
use MyNamespace\MyException;
use MyNamespace\MyObject;

final class MyTest extends TestCase
{
    use AssertThrows; // <--- adds the assertThrows method

    public function testMyObject()
    {
        $obj = new MyObject();

        // Test a basic exception is thrown
        $this->assertThrows(MyException::class, function() use ($obj) {
            $obj->doSomethingBad();
        });

        // Test custom aspects of a custom extension class
        $this->assertThrows(MyException::class, 
            function() use ($obj) {
                $obj->doSomethingBad();
            },
            function($exception) {
                $this->assertEquals('Expected value', $exception->getCustomThing());
                $this->assertEquals(123, $exception->getCode());
            }
        );

        // Test that a specific exception is NOT thrown
        $this->assertNotThrows(MyException::class, function() use ($obj) {
            $obj->doSomethingGood();
        });
    }
}

?>
7
jchook

Die Methode PHPUnit expectException ist sehr unpraktisch, da nur eine Ausnahme pro Testmethode getestet werden kann.

Ich habe diese Hilfsfunktion erstellt, um zu bestätigen, dass einige Funktionen eine Ausnahme auslösen:

/**
 * Asserts that the given callback throws the given exception.
 *
 * @param string $expectClass The name of the expected exception class
 * @param callable $callback A callback which should throw the exception
 */
protected function assertException(string $expectClass, callable $callback)
{
    try {
        $callback();
    } catch (\Throwable $exception) {
        $this->assertInstanceOf($expectClass, $exception, 'An invalid exception was thrown');
        return;
    }

    $this->fail('No exception was thrown');
}

Fügen Sie es Ihrer Testklasse hinzu und rufen Sie diesen Weg auf:

public function testSomething() {
    $this->assertException(\PDOException::class, function() {
        new \PDO('bad:param');
    });
    $this->assertException(\PDOException::class, function() {
        new \PDO('foo:bar');
    });
}
5
Finesse

Hier sind alle Ausnahmebestimmungen, die Sie ausführen können. Beachten Sie, dass alle optional sind.

class ExceptionTest extends PHPUnit_Framework_TestCase
{
    public function testException()
    {
        // make your exception assertions
        $this->expectException(InvalidArgumentException::class);
        // if you use namespaces:
        // $this->expectException('\Namespace\MyExceptio‌​n');
        $this->expectExceptionMessage('message');
        $this->expectExceptionMessageRegExp('/essage$/');
        $this->expectExceptionCode(123);
        // code that throws an exception
        throw new InvalidArgumentException('message', 123);
   }

   public function testAnotherException()
   {
        // repeat as needed
        $this->expectException(Exception::class);
        throw new Exception('Oh no!');
    }
}

Dokumentation finden Sie hier .

4
Westy92
/**
 * @expectedException Exception
 * @expectedExceptionMessage Amount has to be bigger then 0!
 */
public function testDepositNegative()
{
    $this->account->deposit(-7);
}

Seien Sie sehr vorsichtig bei "/**", beachten Sie das doppelte "*". Wenn Sie nur "**" (Asterix) schreiben, wird Ihr Code fehlschlagen. Stellen Sie außerdem sicher, dass Sie die letzte Version von phpUnit verwenden. In einigen früheren Versionen von phpunit @expectedException wird keine Ausnahme unterstützt. Ich hatte 4.0 und es funktionierte nicht für mich, ich musste ein Update auf 5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer durchführen, um mit dem Composer zu aktualisieren.

2

Für PHPUnit 5.7.27 und PHP 5.6 und zum Testen mehrerer Ausnahmen in einem Test war es wichtig, den Ausnahmetest zu erzwingen. Die alleinige Verwendung der Ausnahmebehandlung zum Bestätigen der Instanz von Exception überspringt das Testen der Situation, wenn keine Ausnahme auftritt.

public function testSomeFunction() {

    $e=null;
    $targetClassObj= new TargetClass();
    try {
        $targetClassObj->doSomething();
    } catch ( \Exception $e ) {
    }
    $this->assertInstanceOf(\Exception::class,$e);
    $this->assertEquals('Some message',$e->getMessage());

    $e=null;
    try {
        $targetClassObj->doSomethingElse();
    } catch ( Exception $e ) {
    }
    $this->assertInstanceOf(\Exception::class,$e);
    $this->assertEquals('Another message',$e->getMessage());

}
0
aCiD
function yourfunction($a,$z){
   if($a<$z){ throw new <YOUR_EXCEPTION>; }
}

hier ist der Test

class FunctionTest extends \PHPUnit_Framework_TestCase{

   public function testException(){

      $this->setExpectedException(<YOUR_EXCEPTION>::class);
      yourfunction(1,2);//add vars that cause the exception 

   }

}
0
sami klah