web-dev-qa-db-ja.com

PHPUnitは例外がスローされたことを主張?

テスト対象のコードに例外がスローされたかどうかをテストできるassertまたはそのようなものがあるかどうかを知っている人はいますか?

267
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ドキュメント

PHPUnit作者の記事 例外のテストのベストプラクティスに関する詳細な説明があります。

461
Frank Farmer

docblockアノテーション を使うこともできます。

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

PHP 5.5以降(特に名前空間付きコードの場合)には、 ::class を使うことをお勧めします。

113
David Harkness

PHP 5.5以降で実行している場合、 ::class resolution を使用して expectException/setExpectedException でクラスの名前を取得できます。これにはいくつかの利点があります。

  • 名前はその名前空間(もしあれば)で完全修飾されます。
  • これはstringに解決されるので、あらゆるバージョンのPHPUnitで動作します。
  • あなたのIDEでコード補完を得ます。
  • クラス名を誤って入力すると、PHPコンパイラからエラーが発生します。

例:

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

33
David Harkness

以下のコードは、例外メッセージと例外コードをテストします。

重要:期待される例外も投げられないと失敗します。

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

1回のテスト実行中に複数の例外を表明するには、 assertException extension を使用できます。

TestCaseにmethodを挿入して、

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

私はNiceコードを愛する人のために trait も作りました..

23
hejdav

代替方法は次のようになります。

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

あなたのテストクラスが\PHPUnit_Framework_TestCaseを拡張していることを確認してください。

13
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

包括的なソリューション

例外テストのためのPHPUnitの現在の " ベストプラクティス "は艶がありません( docs )。

私は---現在のexpectExceptionの実装よりも もっと欲しい なので、私は自分のテストケースで使うための特性を作りました。それは 〜50行のコード だけです。

  • テストごとに複数の例外をサポート
  • 例外がスローされた後に呼び出されるアサーションをサポートします
  • 堅牢で明確な使用例
  • 標準のassertの構文
  • メッセージ、コード、クラスだけでなく、アサーションをサポートします。
  • 逆アサーションassertNotThrowsをサポート
  • PHP 7 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();
        });
    }
}

?>
7
jchook

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

これがあなたができるすべての例外アサーションです。それらはすべてオプションであることに注意してください。

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

ドキュメントは こちら で見つけることができます。

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

"/**"については非常に注意してください。二重の "*"に注意してください。 "**"(アスタリスク)のみを書くとコードが失敗します。また、phpUnitの最後のバージョンを使用していることを確認してください。以前のバージョンのphpunit @expectedExceptionでは、例外はサポートされていません。私は4.0を持っていました、そしてそれは私のために働きませんでした、私は5.5にアップデートしなければなりませんでした https://coderwall.com/p/mklvdw/install-phpunit-with-composer 作曲家とアップデートするために。

2
C Cislariu

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

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

ここにテストがあります

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