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

eth*_*ros 25 php phpunit unit-testing

使用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
Run Code Online (Sandbox Code Playgroud)

我想出了以下内容,它完成了这项工作,但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);

}
Run Code Online (Sandbox Code Playgroud)

Nic*_*ini 23

我认为这是单元测试中非常常见的情况.我在这种情况下使用的方法是使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案是最美丽和优雅的,必须是公认的答案. (5认同)
  • 非常好的主意......用一次测试测试很多异常. (4认同)

Ali*_*man 20

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

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

/**
 * @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
}
Run Code Online (Sandbox Code Playgroud)

  • 您还可以使用'@dataProvider注释'传入值(甚至是预期异常的名称 - 使用'$ this-> setExpectedException($ x)').添加新的测试值(会引发异常)将只是dataProvider函数中的另一个数组条目. (4认同)
  • 罗伯特马丁会说要将案件分成不同的测试.在我看来,@ AlisterBulman的答案显示了问题的完美解决方案. (2认同)

dav*_*010 8

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

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