问题描述
这个问题是特定于使用PHPUnit的。
This question is specific to using PHPUnit.
PHPUnit自动将php错误转换为异常。 有没有办法测试一个方法的返回值,该方法会触发一个php错误(内置的错误或用户生成的错误通过 trigger_error )?
PHPUnit automatically converts php errors to exceptions. Is there a way to test the return value of a method that happens to trigger a php error (either built-in errors or user generated errors via trigger_error)?
要测试代码的示例:
function load_file ($file)
{
if (! file_exists($file)) {
trigger_error("file {$file} does not exist", E_USER_WARNING);
return false;
}
return file_get_contents($file);
}
这是我要写的测试类型:
This is the type of test I want to write:
public function testLoadFile ()
{
$this->assertFalse(load_file('/some/non-existent/file'));
}
我遇到的问题是触发错误导致我的单元测试失败(正如它应该)。但是如果我尝试捕获它,或者设置一个预期的异常,那么错误触发后的任何代码都不会执行,所以我无法测试方法的返回值。
The problem I am having is that the triggered error causes my unit test to fail (as it should). But if I try to catch it, or set an expected exception any code that after the error is triggered never executes so I have no way of testing the return value of the method.
这个例子不起作用:
public function testLoadFile ()
{
$this->setExpectedException('Exception');
$result = load_file('/some/non-existent/file');
// code after this point never gets executed
$this->assertFalse($result);
}
任何想法如何实现?
推荐答案
在一个单元测试中无法做到这一点。如果您将测试返回值分解,并将通知分解成两个不同的测试可能。
There is no way to do this within one unit test. It is possible if you break up testing the return value, and the notice into two different tests.
PHPUnit的错误处理程序捕获PHP错误和通知,并将其转换为例外 - 根据定义停止程序执行。你测试的功能根本不会返回。但是,您可以暂时将错误转换为异常,即使在运行时也是如此。
PHPUnit's error handler catches PHP errors and notices and converts them into Exceptions--which by definition stops program execution. The function you are testing never returns at all. You can, however, temporarily disable the conversion of errors into exceptions, even at runtime.
这可能更容易一个例子,所以,这两个测试应该是如:
This is probably easier with an example, so, here's what the two tests should look like:
public function testLoadFileTriggersErrorWhenFileNotFound()
{
$this->setExpectedException('PHPUnit_Framework_Error_Warning'); // Or whichever exception it is
$result = load_file('/some/non-existent/file');
}
public function testLoadFileRetunsFalseWhenFileNotFound()
{
PHPUnit_Framework_Error_Warning::$enabled = FALSE;
$result = load_file('/some/non-existent/file');
$this->assertFalse($result);
}
这也有助于使您的测试更清晰,更清洁和自我记录
This also has the added bonus of making your tests clearer, cleaner and self documenting.
Re:评论:
这是一个很好的问题,我不知道,直到我运行了几个测试。它似乎不会恢复默认/原始值,至少在PHPUnit 3.3.17(现在的稳定版本)之前。
Re: Comment:That's a great question, and I had no idea until I ran a couple of tests. It looks as if it will not restore the default/original value, at least as of PHPUnit 3.3.17 (the current stable release right now).
所以,我实际上修改以上看起来像这样:
So, I would actually amend the above to look like so:
public function testLoadFileRetunsFalseWhenFileNotFound()
{
$warningEnabledOrig = PHPUnit_Framework_Error_Warning::$enabled;
PHPUnit_Framework_Error_Warning::$enabled = false;
$result = load_file('/some/non-existent/file');
$this->assertFalse($result);
PHPUnit_Framework_Error_Warning::$enabled = $warningEnabledOrig;
}
Re:第二个评论:
这不是完全正确的。我正在查看PHPUnit的错误处理程序,它的工作原理如下:
That's not completely true. I'm looking at PHPUnit's error handler, and it works as follows:
- 如果它是一个
E_WARNING
,使用PHPUnit_Framework_Error_Warning
作为异常类。 - 如果它是一个
E_NOTICE
或
E_STRICT
错误,使用PHPUnit_Framework_Error_Notice
- 否则,使用
PHPUnit_Framework_Error
作为异常类。
- If it is an
E_WARNING
, usePHPUnit_Framework_Error_Warning
as an exception class. - If it is an
E_NOTICE
orE_STRICT
error, usePHPUnit_Framework_Error_Notice
- Else, use
PHPUnit_Framework_Error
as the exception class.
所以,是的, E_USER _ *
的错误不会变成PHPUnit * _Warning或* _Notice类,它们仍然转换成一个通用的 PHPUnit_Framework_Error
异常。
So, yes, errors of the E_USER_*
are not turned into PHPUnit's *_Warning or *_Notice class, they are still transformed into a generic PHPUnit_Framework_Error
exception.
其他想法
虽然这完全取决于函数的使用方式,我可能会转而抛出一个实际的异常,而不是触发一个错误,如果是我。是的,这将改变方法的逻辑流程,使用方法的代码...现在执行不会在无法读取文件时停止。但是,这取决于您是否请求的文件不是真正的异常行为。我倾向于使用异常方式,而不是错误/警告/通知,因为它们更容易处理,测试和处理应用程序流程。我通常会保留通知,例如折旧方法调用等。
While it depends exactly on how the function is used, I'd probably switch to throwing an actual exception instead of triggering an error, if it were me. Yes, this would change the logic flow of the method, and the code that uses the method... right now the execution does not stop when it cannot read a file. But that's up to you to decide whether the requested file not existing is truly exceptional behaviour. I tend to use exceptions way more than errors/warnings/notices, because they are easier to handle, test and work into your application flow. I usually reserve the notices for things like depreciated method calls, etc.
这篇关于测试使用PHPUnit触发错误的方法的返回值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!