首页 文章

PHPUnit断言抛出了异常?

提问于
浏览
239

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

12 回答

  • 23

    另一种方法可以是:

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

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

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

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

    Important: 如果没有抛出预期的异常,它将失败 .

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

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

    将方法插入TestCase并使用:

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

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

  • 103
    <?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提供了有关测试异常最佳实践的详细说明 .

  • 27

    你也可以使用docblock annotation

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

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

  • 4

    如果您在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的替代 .

  • 29

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

    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找到 .

  • 8

    PHPUnit目前用于异常测试的“best practices”是......乏善可陈 .

    • 不支持每个测试的多个异常,或者抛出异常后调用的断言

    • 文档缺乏健全或明确的例子

    • 非标准且可能令人困惑的语法("expect" vs "assert")

    • 仅支持消息,代码和类的断言

    • 无反转,例如"expectNoException"

    我为PHPUnit打开了一个Github issue,并立即被维护者解雇了 .

    由于我强烈不同意当前的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();
            });
        }
    }
    
    ?>
    
  • 2

    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');
        });
    }
    
  • 4
    /**
     * @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());
    
    }
    

相关问题