Czy ktoś wie, czy istnieje assert
coś takiego, co może przetestować, czy w testowanym kodzie został zgłoszony wyjątek?
Czy ktoś wie, czy istnieje assert
coś takiego, co może przetestować, czy w testowanym kodzie został zgłoszony wyjątek?
Odpowiedzi:
<?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 () Dokumentacja PHPUnit
Artykuł autora PHPUnit zawiera szczegółowe objaśnienia dotyczące testowania najlepszych praktyk dotyczących wyjątków.
$this->setExpectedException('\My\Name\Space\MyCustomException');
setExpectedException
metoda jest przestarzała, zastąpiona tą expectException
. :)
expectException()
. Choć dla niektórych mogło to być oczywiste, dla mnie była to gotcha .
Możesz także używać adnotacji docblock do czasu wydania PHPUnit 9:
class ExceptionTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testException()
{
...
}
}
W przypadku PHP 5.5+ (szczególnie z kodem przestrzeni nazw) wolę teraz używać ::class
IncorrectPasswordException
powinno wystarczyć - aby komunikat "Wrong password for bob@me.com"
był pomocniczy. Dodaj do tego, że chcesz poświęcić jak najmniej czasu na pisanie testów, a zaczniesz widzieć, jak ważne stają się proste testy.
Jeśli korzystasz z PHP 5.5+, możesz użyć ::class
rozdzielczości, aby uzyskać nazwę klasy za pomocą expectException
/setExpectedException
. Zapewnia to kilka korzyści:
string
tak, więc będzie działać z każdą wersją PHPUnit.Przykład:
namespace \My\Cool\Package;
class AuthTest extends \PHPUnit_Framework_TestCase
{
public function testLoginFailsForWrongPassword()
{
$this->expectException(WrongPasswordException::class);
Auth::login('Bob', 'wrong');
}
}
Kompiluje PHP
WrongPasswordException::class
w
"\My\Cool\Package\WrongPasswordException"
bez PHPUnit jest mądrzejszy.
Uwaga : PHPUnit 5.2 wprowadzony
expectException
jako zamienniksetExpectedException
.
Poniższy kod przetestuje komunikat o wyjątku i kod wyjątku.
Ważne: zakończy się niepowodzeniem, jeśli nie zostanie zgłoszony oczekiwany wyjątek.
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());
}
$this->fail()
nie powinien być używany w ten sposób, nie sądzę, przynajmniej obecnie (PHPUnit 3.6.11); sam stanowi wyjątek. Korzystając z Twojego przykładu, jeśli $this->fail("Expected exception not thrown")
zostanie wywołany, catch
blok zostanie wyzwolony i $e->getMessage()
zostanie wyświetlony komunikat „Oczekiwany wyjątek nie został zgłoszony” .
fail
prawdopodobnie należy po bloku catch, a nie wewnątrz try.
fail
nie powinno być w try
bloku. To samo w sobie wyzwala catch
blok, który daje fałszywe wyniki.
catch(Exception $e)
. Ta metoda działa dla mnie całkiem dobrze, gdy próbuję wychwycić określone wyjątki:try { throw new MySpecificException; $this->fail('MySpecificException not thrown'); } catch(MySpecificException $e){}
Rozszerzenia assertException można użyć do potwierdzenia więcej niż jednego wyjątku podczas jednego wykonania testu.
Wstaw metodę do TestCase i użyj:
public function testSomething()
{
$test = function() {
// some code that has to throw an exception
};
$this->assertException( $test, 'InvalidArgumentException', 100, 'expected message' );
}
Stworzyłem również cechę dla miłośników dobrego kodu ..
assertException
jest zdefiniowany. Nie mogę go również znaleźć w podręczniku PHPUnit.
asertException
Metoda nie jest częścią oryginalnego PHPUnit. Musisz odziedziczyć PHPUnit_Framework_TestCase
klasę i ręcznie dodać metodę podaną w poście powyżej . Twoje przypadki testowe odziedziczą tę odziedziczoną klasę.
Alternatywnym sposobem może być:
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Expected Exception Message');
Upewnij się, że twoja klasa testowa sięga \PHPUnit_Framework_TestCase
.
Metoda PHPUnit expectException
jest bardzo niewygodna, ponieważ pozwala przetestować tylko jeden wyjątek na metodę testową.
Zrobiłem tę funkcję pomocnika, aby zapewnić, że jakaś funkcja zgłasza wyjątek:
/**
* 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');
}
Dodaj go do klasy testowej i wywołaj w ten sposób:
public function testSomething() {
$this->assertException(\PDOException::class, function() {
new \PDO('bad:param');
});
$this->assertException(\PDOException::class, function() {
new \PDO('foo:bar');
});
}
Obecne „ najlepsze praktyki ” PHPUnit dotyczące testowania wyjątków wydają się… brakiem połysku ( dokumenty ).
Ponieważ chciałem więcej niż obecna expectException
implementacja, postanowiłem wykorzystać tę cechę w moich testach. To tylko ~ 50 linii kodu .
assert
składniaassertNotThrows
Throwable
błędy PHP 7Opublikowałem AssertThrows
cechę Github i packagist, aby można ją było zainstalować z kompozytorem.
Aby zilustrować ducha składni:
<?php
// Using simple callback
$this->assertThrows(MyException::class, [$obj, 'doSomethingBad']);
// Using anonymous function
$this->assertThrows(MyException::class, function() use ($obj) {
$obj->doSomethingBad();
});
Dość schludny?
Poniżej znajduje się pełniejszy przykład użycia:
<?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();
});
}
}
?>
public function testException() {
try {
$this->methodThatThrowsException();
$this->fail("Expected Exception has not been raised.");
} catch (Exception $ex) {
$this->assertEquals($ex->getMessage(), "Exception message");
}
}
assertEquals()
jest assertEquals(mixed $expected, mixed $actual...)
odwrotny jak w twoim przykładzie, więc powinien być$this->assertEquals("Exception message", $ex->getMessage());
Oto wszystkie możliwe wyjątki. Pamiętaj, że wszystkie są opcjonalne .
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!');
}
}
Dokumentacja znajduje się tutaj .
/**
* @expectedException Exception
* @expectedExceptionMessage Amount has to be bigger then 0!
*/
public function testDepositNegative()
{
$this->account->deposit(-7);
}
Bądź bardzo ostrożny "/**"
, zauważ podwójne „*”. Pisanie tylko „**” (asterix) zawiedzie w twoim kodzie. Upewnij się także, że używasz ostatniej wersji phpUnit. W niektórych wcześniejszych wersjach phpunit @expectedException Wyjątek nie jest obsługiwany. Miałem 4.0 i nie działało to dla mnie, musiałem zaktualizować do wersji 5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer, aby zaktualizować za pomocą kompozytora.
W przypadku PHPUnit 5.7.27 i PHP 5.6 oraz w celu przetestowania wielu wyjątków w jednym teście ważne było wymuszenie testowania wyjątków. Użycie samej obsługi wyjątków w celu potwierdzenia wystąpienia wyjątku spowoduje pominięcie testowania sytuacji, jeśli nie wystąpi wyjątek.
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>; }
}
tutaj jest test
class FunctionTest extends \PHPUnit_Framework_TestCase{
public function testException(){
$this->setExpectedException(<YOUR_EXCEPTION>::class);
yourfunction(1,2);//add vars that cause the exception
}
}
PhpUnit to niesamowita biblioteka, ale ten konkretny punkt jest nieco frustrujący. Dlatego możemy użyć biblioteki opensource turbotesting-php, która ma bardzo wygodną metodę asercji, która pomaga nam testować wyjątki. Można go znaleźć tutaj:
Aby go użyć, po prostu wykonalibyśmy następujące czynności:
AssertUtils::throwsException(function(){
// Some code that must throw an exception here
}, '/expected error message/');
Jeśli kod, który wpisujemy w funkcji anonimowej, nie zgłasza wyjątku, wyjątek zostanie zgłoszony.
Jeśli kod, który wpisujemy w funkcji anonimowej, zgłasza wyjątek, ale jego komunikat nie pasuje do oczekiwanego wyrażenia regularnego, wyjątek również zostanie zgłoszony.