核心要点
trigger_error()
函数的代码时可能会导致问题。trigger_error()
的代码,可以使用自定义错误处理程序来捕获错误信息,以便稍后使用断言进行分析。这允许代码继续执行,同时仍然允许检查引发的错误条件。假设您正在维护使用 PHP 原生 trigger_error()
函数记录错误信息的代码。同时,您正在使用 PHPUnit 为该代码编写单元测试。如果您参考 PHPUnit 手册,有一节内容专门介绍如何测试错误条件。它描述了 PHPUnit 如何实现自己的错误处理程序,该处理程序将错误、警告和通知转换为异常,并且捕获这些异常是您应该如何处理此类错误测试的方法。但是,根据您的代码外观,您可能会遇到 PHPUnit 的这种方法的问题。本文将详细说明这个问题是什么,它如何影响您测试代码的能力,以及如何解决它。
问题是什么?
错误和异常的行为方式根本不同。与本文特别相关的是,如果传递给它的错误级别常量不表示致命错误,则代码执行可以在 trigger_error()
之后立即继续。当抛出异常时,执行将在找到与该异常类对应的 catch
块的开头继续,这可能在抛出异常的点之后立即发生,也可能不会。让我们来看一些这些行为的示例。首先是错误。
<?php error_reporting(E_ALL | E_STRICT); echo "Before warning\n"; trigger_error("Danger Will Robinson!", E_USER_WARNING); echo "After warning\n"; ?>
如果您运行上述代码,您将获得以下输出:
<code>Before warning PHP Warning: Danger Will Robinson! in /home/matt/error_handler.php on line 4 After warning</code>
由此可见,trigger_error()
调用后的 echo
语句已执行。现在,异常。
<?php try { echo "Before exception\n"; throw new Exception("Danger Will Robinson!"); echo "After exception\n"; } catch (Exception $e) { echo "In catch block\n"; } ?>
输出:
<code>Before exception In catch block</code>
与错误示例相反,抛出异常后的代码未执行。因为 PHPUnit 将错误转换为异常,所以错误在单元测试中的行为与异常相同。在测试期间,任何在触发错误后执行的代码都不会执行。再举一个例子:
<?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 ... } ?>
通过错误到异常的转换,无法测试是否对 $param
进行了有用的处理,因为当错误转换为异常时,该代码将永远不会执行。
PHPUnit 行为的副作用
这种错误到异常的转换会导致代码在开发和测试中的行为与在生产环境中的行为有所不同。这是一个例子:
<?php error_reporting(E_ALL | E_STRICT); echo "Before warning\n"; trigger_error("Danger Will Robinson!", E_USER_WARNING); echo "After warning\n"; ?>
输出:
<code>Before warning PHP Warning: Danger Will Robinson! in /home/matt/error_handler.php on line 4 After warning</code>
第一个 var_dump()
调用(在此期间,将错误转换为异常的自定义错误处理程序正在生效)输出 NULL。第二个 var_dump()
调用(在此期间,PHP 的默认错误处理程序正在生效)输出有关已触发错误的信息。请注意,这不是因为使用了自定义错误处理程序而导致第一个 var_dump()
调用输出 NULL,而是因为该错误处理程序抛出了异常。如果此示例中显示的错误处理程序没有这样做,则第一个 var_dump()
调用的输出将与第二个相同。
解决方案
我们需要一个解决方案,该解决方案允许继续执行正在测试的代码,同时仍然允许我们检查是否引发了错误条件。如上面的示例所示,允许代码执行继续可以使用不将错误转换为异常的自定义错误处理程序来完成。此错误处理程序应该做的是捕获错误信息,以便稍后使用断言进行分析。这就是它的样子:
<?php try { echo "Before exception\n"; throw new Exception("Danger Will Robinson!"); echo "After exception\n"; } catch (Exception $e) { echo "In catch block\n"; } ?>
setUp()
(在每个测试方法之前运行)处理设置错误处理程序,该处理程序只是同一类中的另一个方法,该方法将有关每个错误的信息存储在一个数组中。然后,其他方法(如 assertError()
)由测试方法(如 testDoStuff()
)使用,以对该错误信息执行断言并输出相关的调试信息,例如与预期错误相比触发的错误是什么。其他有用的断言类型包括逻辑反转(即断言未触发特定错误)、检查消息与正则表达式匹配的错误或检查触发的错误数量。
结论
如果您不关心测试触发错误后的逻辑是否仍在执行,则 PHPUnit 的默认行为完全适合您的需求。但是,重要的是您要了解该行为的含义。如果您确实关心此类逻辑的执行,同样重要的是您要知道如何补充 PHPUnit 的功能,以便在尽可能接近生产环境的条件下促进对代码的准确测试。
图片来自 Fotolia
(以下为FAQ,已根据原文内容调整格式和表达,并对部分问题进行了合并或简化)
关于使用 PHPUnit 测试错误条件的常见问题解答 (FAQ)
Q1: 为什么 PHPUnit 在控制台中没有显示任何错误?
PHPUnit 的设计方式允许有效测试错误和异常。如果您在控制台中没有看到任何错误,则 PHPUnit 可能正在捕获它们并将它们视为失败的测试。要查看这些错误的详细信息,可以在运行测试时使用 --debug
选项。这将提供更详细的输出,包括在测试期间捕获的任何错误或异常。
Q2: 如何断言 PHPUnit 中抛出了异常?
PHPUnit 提供了一组专门用于处理异常的断言。最常用的是 expectException()
,您可以使用它来指定您期望抛出的异常类型。如果在测试期间抛出了指定的异常,则测试将通过。如果没有,则测试将失败。这允许您编写专门检查错误条件的正确处理的测试。
Q3: PHP 中的错误报告是如何工作的?
PHP 的错误报告功能允许您控制报告哪些错误以及如何处理它们。默认情况下,所有错误都会被报告并显示。但是,您可以使用 error_reporting()
函数和 display_errors
ini 指令更改这些设置。这允许您隐藏某些类型的错误,或记录错误而不是显示它们。
Q4: 如何在 PHPUnit 中测试异常?
与Q2相同。
Q5: 如何为 PHPUnit 编写测试?
为 PHPUnit 编写测试涉及创建一个新的测试用例类,该类扩展 PHPUnitFrameworkTestCase 类。每个测试都是此类中的一个公共方法,以单词“test”开头。在每个测试方法内部,您可以使用 PHPUnit 的断言来检查您的代码是否按预期运行。例如,您可以使用 assertEquals()
方法来检查函数是否返回预期的结果。
Q6: 如何在 PHPUnit 中处理错误?
PHPUnit 提供了一组专门用于处理错误的断言。最常用的是 expectError()
,您可以使用它来指定您期望触发的错误类型。如果在测试期间触发了指定的错误,则测试将通过。如果没有,则测试将失败。这允许您编写专门检查错误条件的正确处理的测试。
Q7: 如何调试 PHPUnit 中的测试?
PHPUnit 提供了几个调试测试的选项。--debug
选项提供更详细的输出,包括在测试期间捕获的任何错误或异常。--stop-on-error
、--stop-on-failure
和 --stop-on-risky
选项可用于在遇到某种类型的错误时停止测试运行。这可以使识别和修复问题更容易。
Q8: 如何在 PHPUnit 中测试错误条件?
PHPUnit 提供了几种测试错误条件的方法。expectError()
方法允许您指定您期望触发的错误类型。expectWarning()
方法允许您指定您期望触发的警告类型。如果在测试期间触发了指定的错误或警告,则测试将通过。如果没有,则测试将失败。
Q9: 如何在 PHPUnit 中处理警告?
PHPUnit 提供了一组专门用于处理警告的断言。最常用的是 expectWarning()
,您可以使用它来指定您期望触发的警告类型。如果在测试期间触发了指定的警告,则测试将通过。如果没有,则测试将失败。这允许您编写专门检查警告条件的正确处理的测试。
Q10: 如何在 PHPUnit 中使用数据提供程序?
数据提供程序是 PHPUnit 的一个强大功能,允许您使用不同的数据集多次运行测试。要使用数据提供程序,您可以创建一个返回数组的数组的方法。每个内部数组都是测试的一组参数。然后,您使用 @dataProvider
注释您的测试方法,后跟您的数据提供程序方法的名称。然后,PHPUnit 将为每一组参数运行一次测试,并将参数传递给测试方法。
以上是PHP主|使用Phpunit测试错误条件的详细内容。更多信息请关注PHP中文网其他相关文章!