catch - PHPUnit斷言拋出異常?



exception assert (8)

PHPUnit的expectException方法非常不方便,因為它允許每個測試方法只測試一個異常。

我做了這個幫助函數來斷言某些函數拋出一個異常:

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

https://ffff65535.com

有誰知道是否有assert或類似的東西可以測試是否在被測試的代碼中拋出異常?


PHPUnit目前的異常測試“ 最佳實踐 ”是......平淡無奇。

  • 不支持每個測試的多個異常,或者拋出異常後調用的斷言
  • 文檔缺乏可靠或清晰的示例
  • 非標準和可能混淆的語法(“expect”與“assert”)
  • 僅支持消息,代碼和類的斷言
  • 沒有反例,如“expectNoException”

我為PHPUnit打開了一個Github問題 ,並立即被維護人員解僱。

由於我強烈反對當前的expectException實現,因此我在測試用例中使用了一個特徵。

圖書館

AssertThrows特性發布給Github和packagist因此可以與作曲家一起安裝。

簡單的例子

只是為了說明語法背後的精神:

<?php

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

很簡約?

完整的使用示例

下面是一個實際的TestCase類,它顯示了一個更全面的用法示例:

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

?>

以下是您可以執行的所有異常聲明。 請注意,它們都是可選的

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

文檔可以在here找到。


另一種方法可以是以下幾點:

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

請確保您的測試類擴展\ PHPUnit_Framework_TestCase


您也可以使用docblock註釋

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

對於PHP 5.5+(特別是帶有名稱空間的代碼),我現在更喜歡使用::class


您可以使用assertException擴展在一次測試執行期間聲明多個異常。

將方法插入到TestCase中並使用:

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

我也為喜歡漂亮代碼的人製作了一個trait ..


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

"/**"要非常小心,注意雙“*”。 只寫“**”(asterix)會使你的代碼失敗。 還要確保你使用的是phpUnit的最新版本。 在phpunit的一些早期版本中,@expectedException異常不受支持。 我有4.0,並沒有為我工作,我不得不更新到5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer與作曲家更新。


public function testException() {
    try {
        $this->methodThatThrowsException();
        $this->fail("Expected Exception has not been raised.");
    } catch (Exception $ex) {
        $this->assertEquals($ex->getMessage(), "Exception message");
    }

}




assert