回答:
<?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のドキュメント
PHPUnitの著者の記事では、例外のテストのベストプラクティスについて詳しく説明しています。
$this->setExpectedException('\My\Name\Space\MyCustomException');
expectException()
。一部の人にはそれが自明だったかもしれませんが、それは私にとって落とし穴でした。
PHPUnit 9がリリースされるまで、docblockアノテーションを使用することもできます。
class ExceptionTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testException()
{
...
}
}
PHP 5.5以降(特に名前空間のあるコード)では、今は ::class
IncorrectPasswordException
メッセージが等しいこと"Wrong password for bob@me.com"
は補助的である必要があります。それに加えて、テストの記述にできるだけ時間をかけたくない場合、シンプルなテストがいかに重要になるかがわかります。
PHP 5.5以降で実行している場合は、::class
解像度を使用してexpectException
/でsetExpectedException
クラスの名前を取得できます。これにはいくつかの利点があります。
string
ため、どのバージョンのPHPUnitでも動作します。例:
namespace \My\Cool\Package;
class AuthTest extends \PHPUnit_Framework_TestCase
{
public function testLoginFailsForWrongPassword()
{
$this->expectException(WrongPasswordException::class);
Auth::login('Bob', 'wrong');
}
}
PHPコンパイル
WrongPasswordException::class
に
"\My\Cool\Package\WrongPasswordException"
PHPUnitの方が賢明ではありません。
注:PHPUnit 5.2は
expectException
、の代わりとして導入されましたsetExpectedException
。
以下のコードは、例外メッセージと例外コードをテストします。
重要:予想される例外もスローされない場合は失敗します。
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()
少なくとも現時点では(PHPUnit 3.6.11)、このように使用することを意図していません。それ自体が例外として機能します。あなたの例を使用している場合、$this->fail("Expected exception not thrown")
呼ばれ、その後、catch
ブロックがトリガされ$e->getMessage()
ている「例外がスローされません期待します」。
fail
属している可能性があります。
fail
はtry
ブロックにすべきではないので、私は反対票を投じなければなりません。それ自体がcatch
ブロックをトリガーし、誤った結果を生成します。
catch(Exception $e)
。私は特定の例外をキャッチしようとすると、この方法は私のために非常によく動作します:try { throw new MySpecificException; $this->fail('MySpecificException not thrown'); } catch(MySpecificException $e){}
assertException拡張を使用して、1回のテスト実行中に複数の例外をアサートできます。
TestCaseにメソッドを挿入して使用します。
public function testSomething()
{
$test = function() {
// some code that has to throw an exception
};
$this->assertException( $test, 'InvalidArgumentException', 100, 'expected message' );
}
素敵なコードの愛好家のための特性も作りました。
assertException
が、定義されていません。また、PHPUnitのマニュアルにも記載されていません。
asertException
メソッドは、元のPHPUnitの一部ではありません。PHPUnit_Framework_TestCase
クラスを継承し、上記のpostでリンクされたメソッドを手動で追加する必要があります。テストケースは、この継承されたクラスを継承します。
別の方法は次のようになります。
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Expected Exception Message');
テストクラスの範囲を確認してください\PHPUnit_Framework_TestCase
。
PHPUnit expectException
メソッドは、テストメソッドごとに1つの例外のみをテストできるため、非常に不便です。
このヘルパー関数を作成して、一部の関数が例外をスローすることを表明しました。
/**
* 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');
}
それをテストクラスに追加し、次のように呼び出します。
public function testSomething() {
$this->assertException(\PDOException::class, function() {
new \PDO('bad:param');
});
$this->assertException(\PDOException::class, function() {
new \PDO('foo:bar');
});
}
例外テストのためのPHPUnitの現在の「ベストプラクティス」は..欠けているようです(docs)。
現在の実装以上のものを求めていたのでexpectException
、テストケースで使用する特性を作成しました。わずか50行のコードです。
assert
構文assertNotThrows
Throwable
エラーをサポートAssertThrows
トレイトをGithubとpackagistに公開して、composerでインストールできるようにしました。
構文の背後にある精神を説明するためだけに:
<?php
// Using simple callback
$this->assertThrows(MyException::class, [$obj, 'doSomethingBad']);
// Using anonymous function
$this->assertThrows(MyException::class, function() use ($obj) {
$obj->doSomethingBad();
});
かなりきちんと?
より包括的な使用例については、以下を参照してください。
<?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()
ありassertEquals(mixed $expected, mixed $actual...)
、それがあるべきよう、あなたの例のように、逆$this->assertEquals("Exception message", $ex->getMessage());
これが、実行できるすべての例外アサーションです。これらはすべてオプションであることに注意してください。
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!');
}
}
ドキュメントはここにあります。
/**
* @expectedException Exception
* @expectedExceptionMessage Amount has to be bigger then 0!
*/
public function testDepositNegative()
{
$this->account->deposit(-7);
}
に非常に注意してください"/**"
。二重の「*」に注意してください。"**"(アスタリスク)のみを書き込むと、コードが失敗します。また、phpUnitの最新バージョンを使用していることを確認してください。以前のバージョンのphpunitでは、@ expectedException例外がサポートされていません。私は4.0を持っていましたが、うまくいきませんでした。composerで更新するには、https://coderwall.com/p/mklvdw/install-phpunit-with-composerを5.5 に更新する必要がありました。
PHPUnit 5.7.27とPHP 5.6では、1つのテストで複数の例外をテストするために、例外テストを強制することが重要でした。例外処理のみを使用してExceptionのインスタンスをアサートすると、例外が発生しなければ、状況のテストはスキップされます。
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());
}
PhpUnitは素晴らしいライブラリですが、この特定の点は少しイライラします。これが、例外のテストに役立つ非常に便利なアサーションメソッドを持つturbotesting-phpオープンソースライブラリを使用できる理由です。ここにあります:
それを使用するには、次のようにします。
AssertUtils::throwsException(function(){
// Some code that must throw an exception here
}, '/expected error message/');
無名関数の内部で入力するコードが例外をスローしない場合、例外がスローされます。
無名関数の内部で入力したコードが例外をスローしても、そのメッセージが予期される正規表現と一致しない場合は、例外もスローされます。