如何使用PHPUnit测试多个异常?

时间:2009-10-20 11:01:09

标签: php unit-testing phpunit

使用PHPUnit测试异常时,要求每个语句或断言必须抛出异常以便测试通过的最佳方法是什么?

我基本上想做这样的事情:

public function testExceptions()
{

    $this->setExpectedException('Exception');

    foo(-1); //throws exception
    foo(1); //does not throw exception

}

//Test will fail because foo(1) did not throw an exception

我已经提出了以下工作,但这是非常难看的IMO。

public function testExceptions()
{

    try {
        foo(-1);
    } catch (Exception $e) {
        $hit = true;
    }

    if (!isset($hit))
        $this->fail('No exception thrown');

    unset($hit);

    try {
        foo(1);
    } catch (Exception $e) {
        $hit = true;
    }

    if (!isset($hit))
        $this->fail('No exception thrown');

    unset($hit);

}

5 个答案:

答案 0 :(得分:21)

我认为这是单元测试中非常常见的情况。我在这种情况下使用的方法是使用phpunit dataProviders。一切都按预期工作,测试代码变得更加清晰简洁。

class MyTest extends PHPUnit\Framework\TestCase
{
    public function badValues(): array
    {
       return [
           [-1],
           [1]
       ];
    }


    /**
     * @dataProvider badValues
     * @expectedException Exception
     */
    public function testFoo($badValue): void
    {
        foo($badValue);
    }
}

答案 1 :(得分:19)

由于异常是程序流程中的重大事件,因此在单个测试中测试多个事件是有问题的。

最简单的方法是简单地将其拆分为两个测试 - 第一个需要一个异常才能通过,第二个只是简单地运行,并且会失败它会抛出一个。如果你想要的话,你可以在第二个中添加一些其他的测试(可能确认一个返回值),但根据它的命名,我倾向于确保它仍然只做了一件必不可少的事情。

/**
 * @expectedException Exception
 */
public function testBadFooThrowsException()
{
    // optional, can also do it from the '@expectedException x'
    //$this->setExpectedException('Exception');
    foo(-1); //throws exception -- good.
}

public function testFooDoesNotThrowException()
{
    foo(1); //does not throw exception
}

答案 2 :(得分:8)

稍微清洁的代码(但我仍然建议拆分你的测试:

try {
    foo(-1);
    $this->fail('No exception thrown');
} catch (Exception $e) {}

答案 3 :(得分:1)

这对我没有意义。

我猜你试图用一个测试用例测试多个不同的东西,这是不好的做法。

foo()抛出预期的异常时,测试用例成功,bar()将无法运行。

只需创建两个单独的测试用例,这比在第二个列表中生成的代码要少得多。

或解释为什么在bar()因异常而失败后运行foo()会导致异常,这也是有意义的。

答案 4 :(得分:0)

扩展@ dave1010的答案,这就是我解决这个问题的方法。这允许您在一次测试中保持所有这些“断言”干净整洁。您只需定义一个应该使测试失败的变量数组,然后遍历每个变量并查看是否引发了异常。如果任何失败(没有抛出异常),则测试失败,否则测试通过。

<?php

public function testSetInvalidVariableType()
{
    $invalid_vars = array(
        '',                 // Strings
        array(),            // Arrays
        true,               // Booleans
        1,                  // Integers
        new \StdClass       // Objects
    );

    foreach ($invalid_vars as $var) {
        try {
            $object->method($var);
            $this->fail('No exception thrown for variable type "' . gettype($var) . '".');
        } catch (\Exception $expected) {
        }
    }
}