由于foreach警告,PHPUnit期望异常失败

时间:2018-03-09 16:05:14

标签: php unit-testing exception-handling phpunit

我想测试一个名为foo()的方法会抛出异常。问题是我无法获得PHPUnit expectException()来捕获异常。

foo()看起来像这样:

public function foo()
{
    $params = $this->readAndFormatConfig();
    // exception actually gets thrown in this method
    $this->method->throws->exception($params);
}

如果我手动捕获异常,它可以正常工作,如下所示:

public function testFoo()
{
    $badConfig = new Config([]);
    $driver = new bar($badConfig);

    $exceptionThrown = false;
    try {
        $driver->foo();
    } catch (Exception $e) {
        $exceptionThrown = true;
    }
    $this->assertTrue($exceptionThrown);
}

如果我使用expectException捕获它,就像这样:

public function testFoo()
{
    $badConfig = new Config([]);
    $driver = new bar($badConfig);
    $this->expectException(Exception::class);
    $driver->foo();
}

测试失败,我得到了这个例外:

MyTestClass::testFoo Invalid argument supplied for foreach()

get_class($e)的输出是PHPUnit_Framework_Error_Warning让我感到惊讶,但解释了为什么第一次测试有效但第二次测试无效。

我想忽略警告并等到抛出真正的异常,或者获得原始警告,而不是PHPUnit_Framework_Error_Warning

我使用的是php 5.6.32和PHPUnit 5.7.15

1 个答案:

答案 0 :(得分:0)

将以下内容添加到boostrap.php会将警告转换为异常。

function warningToException($errno, $errstr, $errfile, $errline)
{
    throw new Exception($errstr . " on line " . $errline . " in file " . $errfile);
}

set_error_handler("warningToException", E_WARNING);

这允许以下测试通过。

public function testFoo()
{
    $badConfig = new Config([]);
    $driver = new bar($badConfig);
    $this->expectException(Exception::class);
    $driver->foo();
}

我认为更好的方法是在测试中期待PHPUnit_Framework_Error_Warning,如ishegg建议的那样。

我最终实际做的是确保我传递给foreach的对象在进入循环之前是可遍历的。

public function foo()
{
    if (is_array($x) || $x instanceof \Traversable) {
        // do stuff
    } else {
        // return false;
    }
} 

我认为在这种情况下重构应用程序代码更有意义。我真正想要测试的是,如果应用程序配置错误,函数foo返回false,因此在我看来,正确处理错误配置似乎是正确的道路。

如果您出于某种原因偶然发现了这个问题,并且确实需要将警告转换为PHPUnit_Framework_Error_Warning以外的异常类,这就是我的做法。

感谢ishegg指出我正确的方向。