PHPUnit affirme qu'une exception a été lancée?

est-ce que quelqu'un sait s'il y a un assert ou quelque chose comme ça qui peut tester si une exception a été jetée dans le code testé?

229
demandé sur Felipe Almeida 2011-04-16 04:23:39

12 réponses

<?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 documentation

PHPUnit auteur de l'article fournit une explication détaillée sur le test des exceptions meilleures pratiques.

371
répondu Frank Farmer 2017-11-01 13:14:43

vous pouvez également utiliser un annotation docblock :

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

pour PHP 5.5+ (en particulier avec le code namespaced), je préfère maintenant utiliser ::class

100
répondu David Harkness 2017-05-23 11:55:13

si vous utilisez PHP 5.5+, vous pouvez utiliser ::class résolution pour obtenir le nom de la classe avec expectException / setExpectedException . Cela offre plusieurs avantages:

  • le nom sera entièrement qualifié avec son espace de nom (le cas échéant).
  • il se résout à un string de sorte qu'il fonctionnera avec n'importe quelle version de PHPUnit.
  • vous obtenez le code-completion dans votre IDE.
  • le compilateur PHP émettra une erreur si vous vous trompez sur le nom de classe.

exemple:

namespace \My\Cool\Package;

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

PHP compiles

WrongPasswordException::class

en

"\My\Cool\Package\WrongPasswordException"

sans que PHPUnit soit le plus sage.

Note : PHPUnit 5.2 introduit expectException comme un remplacement pour setExpectedException .

29
répondu David Harkness 2016-08-02 00:01:05
Le Code

ci-dessous permet de tester le message d'exception et le code d'exception.

Important: Ce sera un échec si attendu exception levée pas trop.

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());
}
25
répondu Farid Movsumov 2017-11-20 11:19:37

vous pouvez utiliser assertException extension pour faire valoir plus d'une exception lors d'une exécution de test.

insérez la méthode dans votre TestCase et utilisez:

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

j'ai aussi fait un trait pour les amateurs de code de nice..

23
répondu hejdav 2015-10-23 01:42:38
public function testException() {
    try {
        $this->methodThatThrowsException();
        $this->fail("Expected Exception has not been raised.");
    } catch (Exception $ex) {
        $this->assertEquals($ex->getMessage(), "Exception message");
    }

}
8
répondu ab_wanyama 2017-05-03 06:56:13

une autre voie peut être la suivante:

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

veuillez vous assurer que votre classe d'essai s'étend \PHPUnit_Framework_TestCase .

7
répondu Antonis Charalambous 2018-09-20 08:35:14

voici toutes les affirmations d'exception que vous pouvez faire. Notez que tous sont optionnel .

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!');
    }
}

Documentation peut être trouvé ici .

4
répondu Westy92 2017-11-09 09:18:01

PHPUnit actuel " meilleures pratiques , " par exception, les tests sont.. terne.

  • Ne prend pas en charge plusieurs exceptions par test, ou des affirmations appelé après que l'exception est levée
  • Documentation manque de robustesse ou des exemples clairs
  • syntaxe Non standard et pouvant prêter à confusion ("expect "vs" assert")
  • supporte uniquement les assertions pour le message, le code, et classe
  • N'inverse, comme "expectNoException"

j'ai ouvert un GitHub issue pour PHPUnit et a été immédiatement rejetée par le responsable.

comme je ne suis pas du tout d'accord avec la mise en œuvre actuelle de expectException , j'ai fait un trait à utiliser sur mes cas d'essai.

Bibliothèque

Le AssertThrows trait est publié à Github et packagist de sorte qu'il peut être installé avec composer.

Exemple Simple

Juste pour illustrer l'esprit derrière la syntaxe:

<?php

// Within your test case...
$this->assertThrows(MyException::class, function() use ($obj) {
    $obj->doSomethingBad();
});

plutôt soigné?


"1519280920 Complet" Exemple D'Utilisation

Voici une vraie classe de TestCase qui montre un exemple d'utilisation plus complet:

<?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();
        });
    }
}

?>
4
répondu jchook 2018-04-07 03:11:49

la méthode PHPUnit expectException est très incommode parce qu'elle ne permet de tester qu'une seule exception par méthode d'essai.

j'ai fait cette fonction d'assistant pour affirmer qu'une fonction jette une exception:

/**
 * 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');
}

ajoutez-le à votre classe de test et appelez de cette façon:

public function testSomething() {
    $this->assertException(\PDOException::class, function() {
        new \PDO('bad:param');
    });
    $this->assertException(\PDOException::class, function() {
        new \PDO('foo:bar');
    });
}
3
répondu Finesse 2018-05-27 01:48:51
/**
 * @expectedException Exception
 * @expectedExceptionMessage Amount has to be bigger then 0!
 */
public function testDepositNegative()
{
    $this->account->deposit(-7);
}

soyez très prudent sur "/**" , remarquez le double"*". Écrire seulement "** " (Astérix) échouera votre code. Assurez-vous également de votre utilisation de la dernière version de phpUnit. Dans certaines versions antérieures de phpunit @expectedException, L'Exception n'est pas supportée. J'avais 4.0 et ça ne marchait pas pour moi, j'ai dû mettre à jour à 5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer à mettre à jour avec composer.

2
répondu Catalin Cislariu 2017-02-24 00:11:26

Pour PHPUnit 5.7.27 et PHP 5.6 et de tester de multiples exceptions dans un test, il était important de forcer l'exception des tests. L'utilisation de la gestion d'exception seule pour affirmer l'instance D'Exception sautera l'épreuve de la situation si aucune exception ne se produit.

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
répondu aCiD 2018-09-26 04:04:22