PHPUnit断言抛出了异常?

问题描述 投票:264回答:12

有没有人知道是否有一个assert或类似的东西可以测试是否在被测试的代码中抛出异常?

php exception phpunit assert
12个回答
475
投票
<?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 documentation

PHPUnit author article提供了有关测试异常最佳实践的详细说明。


4
投票

这是你可以做的所有异常断言。请注意,所有这些都是可选的。

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


3
投票
/**
 * @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更新与作曲家。


0
投票

对于PHPUnit 5.7.27和PHP 5.6以及在一次测试中测试多个异常,强制进行异常测试非常重要。如果没有异常发生,单独使用异常处理来断言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());

}

116
投票

你也可以使用docblock annotation

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

对于PHP 5.5+(特别是使用命名空间代码),我现在更喜欢使用::class


33
投票

如果您在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 introduced expectException作为setExpectedException的替代品。


27
投票

下面的代码将测试异常消息和异常代码。

重要提示:如果没有抛出预期的异常,它将失败。

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

23
投票

您可以使用assertException extension在一次测试执行期间声明多个异常。

将方法插入TestCase并使用:

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

我也为好的代码爱好者做了一个trait ..


13
投票

另一种方法可以是:

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

请确保您的测试类扩展了\PHPUnit_Framework_TestCase


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

}

7
投票

Comprehensive Solution

PHPUnit目前用于异常测试的“best practices”似乎......乏味(docs)。

由于我wanted more比当前的expectException实现,我做了一个特点用于我的测试用例。这只是~50 lines of code

  • 每个测试支持多个异常
  • 支持抛出异常后调用的断言
  • 强大而清晰的用法示例
  • 标准的assert语法
  • 支持断言不仅仅是消息,代码和类
  • 支持反向断言,assertNotThrows
  • 支持PHP 7 Throwable错误

图书馆

我向Github和AssertThrows发布了packagist特性,因此它可以与作曲家一起安装。

简单的例子

只是为了说明语法背后的精神:

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

?>

6
投票

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, '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');
    });
}
© www.soinside.com 2019 - 2024. All rights reserved.