【问题标题】:PHP Unit Tests: Is it possible to test for a Fatal Error?PHP 单元测试:是否可以测试致命错误?
【发布时间】:2011-06-12 20:00:44
【问题描述】:

FWIW 我正在使用 SimpleTest 1.1alpha。

我有一个单例类,我想编写一个单元测试,通过尝试实例化类来保证该类是单例(它有一个私有构造函数)。

这显然会导致致命错误:

致命错误:调用私有 FrontController::__construct()

有什么方法可以“捕捉”该致命错误并报告通过的测试?

【问题讨论】:

  • 简单测试中没有单元 ;)
  • @Gordon 我看到双关语,但我不明白。
  • 也许this answer可以解释一下
  • 老式的单元测试框架不适合这种情况。为该测试编写 PHPT 并在输出中使用正则表达式将其混合到 PHPUnit/SimpleTest 案例中。

标签: php unit-testing singleton simpletest fatal-error


【解决方案1】:

没有。致命错误会停止脚本的执行。

并没有必要以这种方式测试单例。如果你坚持要检查构造函数是否是私有的,你可以使用ReflectionClass:getConstructor()

public function testCannotInstantiateExternally()
{
    $reflection = new \ReflectionClass('\My\Namespace\MyClassName');
    $constructor = $reflection->getConstructor();
    $this->assertFalse($constructor->isPublic());
}

要考虑的另一件事是,单例类/对象是 TTD 中的一个障碍,因为它们难以模拟。

【讨论】:

    【解决方案2】:

    您可以使用 PHPUnit 的进程隔离之类的概念。

    这意味着测试代码将在php的子进程中执行。这个例子展示了它是如何工作的。

    <?php
    
    // get the test code as string
    $testcode = '<?php new '; // will cause a syntax error
    
    // put it in a temporary file
    $testfile = tmpfile();
    file_put_contents($testfile, $testcode);
    
    exec("php $tempfile", $output, $return_value);
    
    // now you can process the scripts return value and output
    // in case of an syntax error the return value is 255
    switch($return_value) {
        case 0 :
            echo 'PASSED';
            break;
        default :
            echo 'FAILED ' . $output;
    
    }
    
    // clean up
    unlink($testfile);
    

    【讨论】:

    • 在实践中,这适用于检测语法错误,因为 (1) 脚本通常不能独立存在,(2) 像这样引导整个应用程序是不可行的, (3) 它不会创建测试/可重复上下文,(4) 没有设置所有上下文可能会导致错误的致命错误,例如 undefined function。因此,与其执行php $tempfile,不如执行php --no-php-ini --syntax-check $tempfilephp.net/manual/en/features.commandline.options.php
    • 你能证明吗?我不这么认为
    • 好吧,它在控制台中“工作”,因为我看到了致命错误。对于六个无法捕获的错误,$return 始终为 255,否则始终为 0。我想我需要一个关闭处理程序来获取错误代码。 -- 至于 PHPUnit,即使我 @runInSeparateProcess 单个测试导致致命错误,它也始终显示为“E”。 -- 你的想法很有趣,我之前提过你。但要让它工作,我想我需要深入研究 PHPUnit 并编写一个补丁或插件。我想知道为什么以前没有人这样做。期望脚本失败是不合理的吗?
    • 现在我明白了你的担忧。会玩一下PHPUnit,可能会写一些代码给你反馈..
    • 我发现有一个可自定义的隔离template。我们需要register_shutdown_function('__phpunit_shutdown', $test, $result)__phpunit_shutdown($test, $result)(在出现错误的情况下)只像往常一样打印一个序列化数组,但添加了一个 error 键设置为 error_get_last()。然后我们可以添加对来自PHPUnit_Util_PHP::runTestJob@expectedShutdownError &lt;code&gt; 的支持,这将使用修改过的参数(主要是stderr = '')调用processChildResult
    【解决方案3】:

    这是 Mchl 答案的完整代码 sn-p,因此人们不必阅读文档...

    public function testCannotInstantiateExternally()
    {
        $reflection = new \ReflectionClass('\My\Namespace\MyClassName');
        $constructor = $reflection->getConstructor();
        $this->assertFalse($constructor->isPublic());
    }
    

    【讨论】:

      猜你喜欢
      • 2015-12-28
      • 1970-01-01
      • 2015-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-18
      相关资源
      最近更新 更多