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

2022-08-30 14:49:53

在使用 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);

}

答案 1

我认为这是单元测试中非常普遍的情况。在这种情况下,我使用的方法是使用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);
    }
}

答案 2

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

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

/**
 * @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
}

推荐