Est-ce que quelqu'un sait s'il existe une assert
ou quelque chose comme ça qui peut vérifier si une exception a été générée dans le code testé?
<?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 () documentation PHPUnit
PHPUnit author article fournit des explications détaillées sur les meilleures pratiques en matière de test des exceptions.
Vous pouvez également utiliser une annotation docblock :
class ExceptionTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testException()
{
...
}
}
Pour PHP 5.5+ (en particulier avec du code namespaced), je préfère maintenant utiliser ::class
Si vous exécutez PHP 5.5+, vous pouvez utiliser ::class
resolution pour obtenir le nom de la classe avec expectException
setExpectedException
. Cela offre plusieurs avantages:
string
afin qu'il fonctionne avec toutes les versions de PHPUnit.Exemple:
namespace \My\Cool\Package;
class AuthTest extends \PHPUnit_Framework_TestCase
{
public function testLoginFailsForWrongPassword()
{
$this->expectException(WrongPasswordException::class);
Auth::login('Bob', 'wrong');
}
}
PHP compile
WrongPasswordException::class
dans
"\My\Cool\Package\WrongPasswordException"
sans PHPUnit le plus sage.
_/Note: PHPUnit 5.2 introduit
expectException
en remplacement desetExpectedException
.
Le code ci-dessous testera le message d'exception et le code d'exception.
Important: Il échouera si une exception attendue n'est pas levée également.
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());
}
Vous pouvez utiliser extension assertException pour affirmer plusieurs exceptions lors de l'exécution d'un test.
Insérer une méthode dans votre TestCase et utiliser:
public function testSomething()
{
$test = function() {
// some code that has to throw an exception
};
$this->assertException( $test, 'InvalidArgumentException', 100, 'expected message' );
}
J'ai aussi créé un trait pour les amoureux du code de Nice.
Une autre manière peut être la suivante:
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Expected Exception Message');
Assurez-vous que l'étendue de votre classe de test est \PHPUnit_Framework_TestCase
.
public function testException() {
try {
$this->methodThatThrowsException();
$this->fail("Expected Exception has not been raised.");
} catch (Exception $ex) {
$this->assertEquals($ex->getMessage(), "Exception message");
}
}
Les " meilleures pratiques " actuelles de PHPUnit pour le test des exceptions semblent .. terne ( docs ).
Étant donné que je suis tout à fait en désaccord avec la mise en œuvre actuelle de expectException
, j'ai créé un trait à utiliser dans mes cas de test. Ce n'est que 50 lignes .
assert
assertNotThrows
J'ai publié le AssertThrows
trait en Github et packagist afin qu'il puisse être installé avec composer.
Juste pour illustrer l'esprit derrière la syntaxe:
<?php
// Using simple callback
$this->assertThrows(MyException::class, [$obj, 'doSomethingBad']);
// Using anonymous function
$this->assertThrows(MyException::class, function() use ($obj) {
$obj->doSomethingBad();
});
Génial?
Veuillez voir ci-dessous pour 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();
});
}
}
?>
La méthode PHPUnit expectException
est très gênante car elle ne permet de tester qu'une seule exception par méthode.
J'ai créé cette fonction d'assistance pour affirmer qu'une fonction lève 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');
});
}
Voici toutes les assertions d'exception que vous pouvez faire. Notez qu'ils sont tous optionnels.
class ExceptionTest extends PHPUnit_Framework_TestCase
{
public function testException()
{
// make your exception assertions
$this->expectException(InvalidArgumentException::class);
// if you use namespaces:
// $this->expectException('\Namespace\MyException');
$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!');
}
}
La documentation peut être trouvée ici .
/**
* @expectedException Exception
* @expectedExceptionMessage Amount has to be bigger then 0!
*/
public function testDepositNegative()
{
$this->account->deposit(-7);
}
Faites très attention à "/**"
, remarquez le double "*". Écrire seulement "**" (astérix) fera échouer votre code . Assurez-vous également que vous utilisez la dernière version de phpUnit. Dans certaines versions antérieures de phpunit, @expectedException Exception n'est pas pris en charge. J'avais 4.0 et cela ne fonctionnait pas pour moi, je devais mettre à jour vers 5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer pour mettre à jour avec composer.
Pour PHPUnit 5.7.27 et PHP 5.6 et pour tester plusieurs exceptions dans un test, il était important de forcer le test des exceptions. L'utilisation de la gestion des exceptions seule pour affirmer l'instance d'Exception évite de tester 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());
}
function yourfunction($a,$z){
if($a<$z){ throw new <YOUR_EXCEPTION>; }
}
voici le test
class FunctionTest extends \PHPUnit_Framework_TestCase{
public function testException(){
$this->setExpectedException(<YOUR_EXCEPTION>::class);
yourfunction(1,2);//add vars that cause the exception
}
}