【问题标题】:PHPUnit expect exception failing due to foreach warning由于 foreach 警告,PHPUnit 期望异常失败
【发布时间】:2018-08-18 06:10:22
【问题描述】:

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

【问题讨论】:

  • 您的foo() 方法似乎有问题...该错误告诉您foreach() 有问题。 PHPUnit 可能会从 PHP 抛出的警告中产生一个异常,所以这就是为什么你得到那个异常而不是你期望的那个。
  • ishegg 在开发中,警告也是一个例外,但它是我所期望的类型。如果我按照我在测试中的方式在 dev 中配置类,我会得到这个异常Whoops \ Exception \ ErrorException (E_WARNING) Invalid argument supplied for foreach()。你知道如何阻止 PHPUnit 改变异常类并抛出原来的警告/异常吗?
  • 您使用什么代码将 PHP Warnings 转换为 ErrorExceptions?
  • 我猜 Whoops 实际上并没有在你的测试中运行,所以你没有得到你期望的 ErrorException...

标签: php unit-testing exception-handling phpunit


【解决方案1】:

将以下内容添加到 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 返回 false,因此在我看来正确处理错误配置似乎是正确的路径。

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

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

【讨论】:

    猜你喜欢
    • 2015-10-07
    • 2021-06-21
    • 2014-06-18
    • 1970-01-01
    • 2017-02-21
    • 2017-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多