PHPUnit 期望异常因 foreach 警告而失败

PHPUnit expect exception failing due to foreach warning

我想测试名为 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

将以下内容添加到 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();
}

我认为更好的方法是按照 ishegg 的建议在测试中预期 PHPUnit_Framework_Error_Warning

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

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

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

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

感谢 ishegg 为我指明了正确的方向。