phpunit 验收测试_使用PHPUnit进行错误条件测试

phpunit 验收测试

Let’s say you’re maintaining code that uses PHP’s native trigger_error() function to log error information. Let’s also say that you’re in the process of using PHPUnit to write unit tests for that code.

假设您正在维护使用PHP的本机trigger_error()函数记录错误信息的代码。 我们还要说,您正在使用PHPUnit为该代码编写单元测试。

If you refer to the PHPUnit manual, there’s a section that deals with testing for error condition. It describes how PHPUnit implements its own error handler that converts errors, warnings, and notices into exceptions and that catching those exceptions is how you should handle testing for these types of errors.

如果您参考PHPUnit手册,则有一节专门讨论错误条件的测试 。 它描述了PHPUnit如何实现自己的错误处理程序,该错误处理程序将错误,警告和通知转换为异常,并且捕获这些异常是您应如何处理这些类型的错误的测试。

However, depending on what your code looks like, it’s possible that you’ll run into a problem with PHPUnit’s approach to this. This article will detail what this problem is, how it impacts your ability to test your code, and how to go about solving it.

但是,根据代码的外观,PHPUnit的处理方法可能会遇到问题。 本文将详细说明这个问题是什么,它如何影响您测试代码的能力以及如何解决它。

有什么问题? (What’s the Problem?)

Errors and exceptions behave in fundamentally different ways. Of particular relevance to this article is the fact that code execution can continue at the point immediately after trigger_error() if the error level constant passed to it is not indicative of a fatal error. When an exception is thrown, execution will continue at the beginning of a catch block found to correspond to the class of that exception, which may or may not be immediately after the point at which the exception is thrown.

错误和异常的行为从根本上不同。 与本文特别相关的一个事实是,如果传递给错误级别常量错误级别常量不表示致命错误,则代码执行可以在trigger_error()之后立即继续执行。 当引发异常时,执行将在发现的异常对应的catch块的开始处继续执行,该捕获块可能会或可能不会紧接在引发异常的那一点之后。

Let’s look at some examples of these behaviors. First, errors.

让我们看一下这些行为的一些例子。 首先,错误。

<?php
error_reporting(E_ALL | E_STRICT);
echo "Before warningn";
trigger_error("Danger Will Robinson!", E_USER_WARNING);
echo "After warningn";

You’ll get the following output if you run the above code:

如果运行上面的代码,您将获得以下输出:

Before warning
PHP Warning:  Danger Will Robinson! in /home/matt/error_handler.php on line 4
After warning

From this we see that the echo statement after the trigger_error() call is executed.

由此可见,执行trigger_error()调用之后的echo语句。

Now, exceptions.

现在,例外。

<?php
try {
    echo "Before exceptionn";
    throw new Exception("Danger Will Robinson!");
    echo "After exceptionn";
}
catch (Exception $e) {
    echo "In catch blockn";
}

And the output:

并输出:

Before exception
In catch block

In contrast to the example case for errors, the code after the exception was thrown is not executed. Because PHPUnit converts errors to exceptions, errors behave the same way in unit tests as exceptions do. Any code that follows an error being triggered will not executed while it is being tested.

与示例错误相反,抛出异常后的代码不执行。 因为PHPUnit将错误转换为异常,所以错误在单元测试中的行为与异常相同。 在测试错误后,将不会执行跟随错误被触发的任何代码。

Here’s another example:

这是另一个例子:

<?php
function foo($param) {
    if (is_string($param)) {
        trigger_error(__FUNCTION__ . " no longer supports strings, pass an array", E_USER_NOTICE);
    }
    // do useful stuff with $param
    ...
}

With error-to-exception conversion, there’s no way to test if useful stuff is done with $param because that code will never be executed when the error is converted into an exception.

使用错误到异常的转换,无法测试$ param是否完成了有用的工作,因为当错误转换为异常时,该代码将永远不会执行。

PHPUnit行为的副作用 (Side Effects of PHPUnit’s Behavior)

This error-to-exception conversion causes differences from how the code will behave in development and testing than how it will behave in production. Here’s an example:

这种从异常到异常的转换导致代码在开发和测试中的行为方式与生产中的行为方式有所不同。 这是一个例子:

<?php
function error_handler($errno, $errstr) {
    throw new Exception($errstr);
}
set_error_handler("error_handler");

try {
    trigger_error("Danger Will Robinson!", E_USER_WARNING);
}
catch (Exception $e) {
    var_dump(error_get_last());
}
restore_error_handler();
trigger_error("Danger Will Robinson!", E_USER_WARNING);
var_dump(error_get_last());

Here’s its output:

这是它的输出:

NULL
PHP Warning:  Danger Will Robinson! in /home/matt/exception_converter.php on line 16
array(4) {
  ["type"]=>
  int(512)
  ["message"]=>
  string(21) "Danger Will Robinson!"
  ["file"]=>
  string(59) "/home/matt/exception_converter.php"
  ["line"]=>
  int(14)
}

The first var_dump() call, during which the custom error handler that converts errors to exceptions is in effect, outputs NULL. The second var_dump() call, during which PHP’s default error handler is in effect, outputs information about the error that was triggered.

在第一个var_dump()调用期间,将错误转换为异常的自定义错误处理程序生效,并输出NULL。 第二个var_dump()调用(在此过程中,PHP的默认错误处理程序有效)将输出有关已触发错误的信息。

Note that it’s not because a custom error handler is used that the first var_dump() call outputs NULL, but because that error handler throws an exception. If the error handler shown in this example did not do that, the first var_dump() call would have the same output as the second.

请注意,这不是因为使用自定义错误处理程序使第一个var_dump()调用输出NULL,而是因为该错误处理程序引发了异常。 如果此示例中显示的错误处理程序没有执行此操作,则第一个var_dump()调用将具有与第二个相同的输出。

解决方案 (The Solution)

We need a solution that allows for the execution of code being tested to continue while still allowing us to check that an error condition was raised. As above examples showed, allowing code execution to continue can be done using a custom error handler that doesn’t convert errors to exceptions. What this error handler should do instead is capture error information for later analysis with assertions. Here’s what this might look this:

我们需要一种解决方案,允许继续执行被测试的代码,同时仍然允许我们检查是否出现了错误情况。 如上述示例所示,可以使用不会将错误转换为异常的自定义错误处理程序来完成允许代码继续执行的功能。 该错误处理程序应该执行的操作是捕获错误信息,以便以后使用断言进行分析。 这可能是这样的:

<?php
class MyTest extends PHPUnit_Framework_TestCase
{
    private $errors;

    protected function setUp() {
        $this->errors = array();
        set_error_handler(array($this, "errorHandler"));
    }

    public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) {
        $this->errors[] = compact("errno", "errstr", "errfile",
            "errline", "errcontext");
    }

    public function assertError($errstr, $errno) {
        foreach ($this->errors as $error) {
            if ($error["errstr"] === $errstr
                && $error["errno"] === $errno) {
                return;
            }
        }
        $this->fail("Error with level " . $errno .
            " and message '" . $errstr . "' not found in ", 
            var_export($this->errors, TRUE));
    }

    public function testDoStuff() {
        // execute code that triggers a warning
        $this->assertError("Message for the expected error",
            E_USER_WARNING);
    }
}

setUp(), which is run before each test method, handles setting up the error handler which is just another method in the same class that stores information about each error in an array. Other method like assertError() are then used by test methods like testDoStuff() to perform assertions against that error information and output relevant debugging information, like what errors were triggered compared to what errors were expected.

在每个测试方法之前运行的setUp()处理设置错误处理程序,该错误处理程序只是同一类中的另一个方法,该方法将有关每个错误的信息存储在数组中。 然后,诸如testDoStuff()类的测试方法使用诸如assertError()类的其他方法来针对该错误信息执行断言并输出相关的调试信息,例如与预期的错误相比,触发了哪些错误。

Other useful types of assertions include logical inversions (i.e. asserting that a specific error was not triggered), checking for errors with messages that match regular expressions, or checking the number of errors triggered.

其他有用的断言类型包括逻辑反转(即断言未触发特定错误),使用与正则表达式匹配的消息检查错误或检查触发的错误数。

结论 (Conclusion)

In instances where you don’t care about testing that the logic following a triggered error is still executed, PHPUnit’s default behavior is perfectly suitable for your needs. However, it’s important that you be aware of the implications of that behavior.

在您不关心测试触发错误后的逻辑是否仍然执行的情况下,PHPUnit的默认行为非常适合您的需求。 但是,重要的是要注意该行为的含义。

In cases where you do care about the execution of such logic, it’s equally important that you know how to supplement PHPUnit’s functionality to facilitate accurate testing of your code is conditions as close to those of your production environment as is feasible.

如果您确实关心这种逻辑的执行,那么了解如何补充PHPUnit的功能以促进对代码的准确测试(在可行的情况下尽可能接近生产环境的条件)也同样重要。

Image via Fotolia

图片来自Fotolia

翻译自: https://www.sitepoint.com/testing-error-conditions-with-phpunit/

phpunit 验收测试

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值