【问题标题】:phpUnit - mock php extended exception objectphpUnit - 模拟 php 扩展异常对象
【发布时间】:2011-02-19 08:33:35
【问题描述】:

我正在测试一些扩展默认 php 异常对象的遗留代码。此代码打印出自定义 HTML 错误消息。

我想模拟这个异常对象,当测试代码生成异常时,它只会回显基本消息,而不是给我整个 HTML 消息。

我想不出办法来做到这一点。似乎您可以测试显式异常,但不能以一般方式更改异常的行为,也不能模拟扩展默认 php 功能的对象。 (除了例外,想不出另一个例子……但似乎是这样)

我想问题是,你会将模拟对象附加到哪里?看起来你不能干涉'throw new',这是调用对象方法的地方......

或者,如果您可以以某种方式使用现有的 phpunit 异常功能以您想要的方式更改异常行为,以您所有代码的通用方式...但这似乎是 hacky 和糟糕的......

编辑:这里有一些代码可以让事情更清楚:

class FooTest extends PHPUnit_Framework_TestCase{

    public function testBar(){
        include '/path/to/file.php'; //generates exception

        $this->assertTrue($baz);             
    }
}
 ...
//overridden exception class
class Foo_Exception extends ErrorException{
 ...

所以,我的问题是,有没有办法处理这个被覆盖的类,而不是根据具体情况进行处理?如果我不测试异常的行为,只测试导致异常的代码怎么办?

【问题讨论】:

  • 好吧,我现在有点糊涂了。包含中的异常没有被捕获,然后我的第一个答案成立,或者它被捕获并且我的第二个答案成立。与它无关的异常类型。
  • 你是对的...我对 ob_start 将如何处理事情感到困惑...但是...您的解决方案确实可以抑制错误消息,但这也意味着它会处理所有输出同样......我想我是在询问一个更具体的解决方案来处理异常类本身......但现在我一直认为这似乎不可行......或者不一定是可取的。 ..我想处理对象行为的最佳情况是为每种情况引发异常。有时,只有当你问一个模糊的问题时,事情才有意义....

标签: php unit-testing exception mocking phpunit


【解决方案1】:

扩展的 PHP 异常对象“打印”一个服装 HTML 错误页面?你的意思是它的错误信息是整个 HTML 页面?这不是很聪明...

您可以做的是替换默认的异常处理程序(请参阅this function),在异常上调用 getMessage 并解析 HTML 错误页面以提取消息。然后您可以打印错误消息并终止脚本。像这样(在 PHP 5.3 中):

set_exception_handler(
    function (Exception $e) {
        die(parse_html_error_page($e->getMessage()));
    }
);

【讨论】:

  • 好吧,脚本在包含用于输出给用户的 HTML 文件之前,会以一些较小的方式处理错误,并带有“漂亮”格式的消息。我同意这可能不是最模块化的方法......不过,我认为这不会起作用,因为这个错误处理类正在为脚本中捕获的错误提供消息。 set_error_handler 仅适用于未捕获的错误......
【解决方案2】:

好的,我误解了这个问题。如果您正在测试的脚本捕捉到错误然后回显错误页面,那么这与异常无关。您可以使用 ob_ 系列:

ob_start();
include $file;
$contents = ob_get_contents();

if (result_is_error($contents))
    die(extract_error_from_result($contents));
else
    echo $contents;

ob_end_clean();

【讨论】:

  • 我应该包含一些代码或伪代码以使其更清晰,但我认为这也行不通:这个线程说即使在缓冲输出时你仍然会看到抛出的异常.... stackoverflow.com/questions/2201841/… 在我深入研究代码之后,看起来错误来自比我最初想象的更多的地方......我想也许我只是写了一个定义不明确的问题......
  • 如果它们没有被捕获并且异常处理程序吐出错误消息并终止脚本,您可能会看到抛出的异常。我不确定这是否是默认异常处理程序的行为,但即使是这样,它也不会在捕获异常时应用。
【解决方案3】:

我将首先编写一个捕获异常生成行为的测试:

include '/path/to/file.php'; //generates exception
public function testCatchFooException() {
    try {
        $this->assertTrue($baz);             
    }
    catch (Exception $expected) {
        $this->assertEquals('This is expected html from exception', $expected->getMessage());
        return;
    }

    $this->fail('An expected Exception has not been raised Foo_Excpetion.');
}

现在您可以使用此覆盖率测试做几件事。您可以修复异常,也可以修复导致异常的代码。

您可以做的另一件事是将整个 file.php 包装在一个类中:

 class FooClass {

    function runFoo() {
        include '/path/to/file.php'; //generates exception

    }   

}

然后在使用 extract 方法的同时添加测试,直到你隔离异常。

[编辑]

这是一些严重的程序遗留代码:

<?php
require_once 'helper.php';  //helper file

function countNewMessages($user_id) {
}

function countNewOrders() {
}

function countNewReturns() {
}

function getDB($init = NULL) {
}

function getDisplay() {
}

getDisplay();

?>

这是包装好的类:

<?php
require_once '';  //helper file

class Displayer {
    function countNewMessages($user_id) {
    }

    function countNewOrders() {
    }

    function countNewReturns() {
    }

    function getDB($init = NULL) {
    }

    function getDisplay() {
    }
}
?>

现在我可以测试它了:

    function testGetDisplay() {
    $display = new Displayer();

    $this->assertEquals('html code', $display->getDisplay());
}

并测试其中的各个功能。如果我能在上面进一步发芽方法。

上述测试将被视为覆盖测试。它可能存在错误,但这就是它的作用。因此,当我发芽方法时,通过发芽从测试中获得更多代码覆盖率,我可以确保不会破坏输出。

【讨论】:

  • 你能解释一下你的第二个例子吗?测试会是什么样子?你会 $foo_instance = new FooClass ... 然后在测试中捕获 ... $foo_instance->runFoo() ...??
  • 这是我从 Michael Feather 的书 WEWLC 中得到的。无论如何,这都是一个对象。查看我的编辑。
猜你喜欢
  • 2014-11-07
  • 1970-01-01
  • 2014-03-27
  • 2018-07-22
  • 2021-10-31
  • 2012-09-26
  • 1970-01-01
  • 2017-11-18
  • 2011-03-09
相关资源
最近更新 更多