Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/237.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHPUnit-如何将调用非set对象上的方法的错误转化为失败的测试而不是错误_Php_Design Patterns_Phpunit - Fatal编程技术网

PHPUnit-如何将调用非set对象上的方法的错误转化为失败的测试而不是错误

PHPUnit-如何将调用非set对象上的方法的错误转化为失败的测试而不是错误,php,design-patterns,phpunit,Php,Design Patterns,Phpunit,我有一个类,它使用责任链模式。简而言之,在某些条件下,如果调用了它的一个方法,它会将调用传递给后继方法的同一个方法(它和后继方法共享同一个接口) 例如: catch(PDOException $exception) { if(isset($this->successor)) { $this->successor->log($log); } } 基本上,如果继任者已经确定,它将被调用。如果没

我有一个类,它使用责任链模式。简而言之,在某些条件下,如果调用了它的一个方法,它会将调用传递给后继方法的同一个方法(它和后继方法共享同一个接口)

例如:

catch(PDOException $exception)
    {
        if(isset($this->successor))
        {
            $this->successor->log($log);
        }
    }
基本上,如果继任者已经确定,它将被调用。如果没有,什么也不会发生

目前,在我的单元测试中,我有两个测试:在其中一个测试中,设置了后继者,并在正确的条件下调用该方法以触发对后继者的调用。继任者是一个mock,我可以测试是否调用了正确的方法

现在,在编写
if
语句之前,我复制了相同的测试,但删除了设置后续对象的代码。当我运行测试时,不出所料,测试会因为一个错误而停止,因为SUT试图调用一个不存在的对象上的方法

当我实现代码(如上所述)时,所有测试都顺利通过

不过我不高兴。我遵循TDD方法学,我希望在编写代码之前能够看到失败的测试,而不是错误


我如何重构它,以便首先测试失败,而不是出错?

将单元测试放入TRY-CATCH块。如果捕获到异常,可以将其转换为故障:

try {
    ...testing
} catch (Exception $e) {
    $this->assertTrue(false, $e->getMessage());
}

将单元测试放在TRY-CATCH块中。如果捕获到异常,可以将其转换为故障:

try {
    ...testing
} catch (Exception $e) {
    $this->assertTrue(false, $e->getMessage());
}

可悲的是,这是不可避免的。PHP引发致命错误(),该错误将终止进程。PHPUnit不能拦截它以产生错误或失败,您的代码也不能

$ php -r 'try { $o = null; $o->foo(); } catch (Exceptiion $e) { echo "fail"; }'

Fatal error: Call to a member function foo() on a non-object in Command line code on line 1
您所能做的最多就是检测a中的错误并转储一些诊断输出。无法从致命错误中恢复:(


至于TDD,我相信目标是编写尽可能多的测试代码以使测试不通过。这似乎是一个微妙的区别,但这意味着失败(
F
)或错误(
E
)或死亡(停止运行)。一旦达到目标,编写代码以使测试通过。

遗憾的是,这是不可避免的。PHP引发了一个致命错误()PHPUnit不能拦截它以产生错误或失败,您的代码也不能

$ php -r 'try { $o = null; $o->foo(); } catch (Exceptiion $e) { echo "fail"; }'

Fatal error: Call to a member function foo() on a non-object in Command line code on line 1
您最多只能检测a中的错误并转储一些诊断输出。无法从致命错误中恢复:(


至于TDD,我认为目标是编写尽可能多的测试代码,以使您的测试不通过。这似乎是一个微妙的区别,但这意味着失败(
F
)或错误(
E
)或死亡(停止运行)。一旦你到达那里,就编写代码让测试通过。

失败的测试意味着发生了与预期不同的事情。错误意味着,有些事情不仅是意外的,而且已经中断了。我建议仍然将错误视为错误。在你的情况下,甚至是测试也会中断,因为(看起来)您允许
null
作为属性,但您没有正确处理它。添加到上面的注释中:TDD说编写使测试失败的最小代码。这意味着在测试过程中不会发生错误。否则,您将以检查类是否存在、是否定义了方法等愚蠢的测试而告终。失败的测试意味着不同发生在预期的情况下。错误意味着,某些事情不仅仅是意外的,而且已经被破坏了。我建议仍然将错误视为错误。在您的情况下,甚至是测试也被破坏了,因为(看起来)您允许
null
作为属性,但您没有正确处理它。添加到上面的注释中:TDD说编写最小的代码,这将使您的测试失败。这意味着在测试过程中不会发生错误。否则,您将进行愚蠢的测试,检查是否存在类、是否定义了方法等。-1这将不起作用,因为在非对象会导致致命错误——不是异常。-1这不起作用,因为对非对象调用方法会导致致命错误——不是异常。我明白了。我认为TDD只需要编写一个存根,然后编写测试。但你是说允许一小部分功能,使测试失败,而不是抛出错误?St从工作代码开始编程(编译、运行并通过所有测试),您只需编写足够的测试代码,即可使测试无法通过。在Java等语言中,这往往意味着它无法编译。在PHP中,这可能意味着进程因致命错误而死亡。在这两种语言中,测试中的错误或失败也是可以接受的。然后,您只需编写足够的生产代码,即可使测试通过。冲洗并重复。因此,出现错误在测试中是可以接受的,在编写使测试通过的代码之前?是的,运行测试时出现错误意味着测试不通过。这就是在生产代码中修复错误以使测试通过的点。我明白了。我认为TDD只需要编写一个存根,然后编写测试。但你是说允许使用一个小级别的功能ed,使测试失败,而不是抛出错误?从工作代码开始(编译、运行并通过所有测试),您只需编写足够的测试代码,即可使测试无法通过。在Java等语言中,这往往意味着它无法编译。在PHP中,这可能意味着进程因致命错误而死亡。在这两种语言中,测试中的错误或失败也是可以接受的。然后,您只需编写足够的生产代码,即可使测试通过。冲洗并重复。因此,出现错误在测试中,在编写使测试通过的代码之前是否可以接受?是的,运行测试时出现错误意味着测试不通过。这就是在生产代码中修复错误以使测试通过的点。