我有一套复杂的PHPUnit测试,其中一些涉及连接到世界各地的服务器,无论出于何种原因,有时会超时。
在服务器超时时,我不想让测试失败,而是在实际将其标记为失败之前,只需重试该测试一次或多次。
现在,我知道这可能不是处理我手头情况的最好方法。一个更好的解决方案是修复服务器。但是,现在这是我无法控制的。
所以,我真正喜欢的是告诉PHPUnit重新测试每个失败的测试用例X次的方法,并且只有在每次失败时才将其标记为失败。
有什么想法吗?
编辑:很多人都回复了有用的建议,我不这样做。我明白了,谢谢。但是,具体而言,我要创建一个测试套件来测试完整系统的操作,包括远程服务器。我理解测试代码某些部分的概念来自外界的“模拟”反应...但如果我的部分测试测试“完整堆栈”,我晚上睡得更好。
答案 0 :(得分:10)
由于PHPUnit不支持开箱即用的这种行为,因此您需要自己编写循环代码。而不是在每个需要它的测试中执行它,创建一个自定义测试用例基类(如果你还没有)扩展PHPUnit_Framework_TestCase
并提供该功能。
您可以获得幻想并覆盖testBare()
以检查注释,例如@retry 5
,循环那么多次,调用parent::testBare()
,并吞下所有异常(或子集)除了最后一个。
public function runBare() {
// I'll leave this part to you. PHPUnit supplies methods for parsing annotations.
$retryCount = $this->getNumberOfRetries();
for ($i = 0; $i < $retryCount; $i++) {
try {
parent::runBare();
return;
}
catch (Exception $e) {
// last one thrown below
}
}
if ($e) {
throw $e;
}
}
或者您可以创建一个类似的辅助方法,该方法将重试次数和闭包/可调用作为参数,并从需要它的每个测试中调用它。
public function retryTest($count, $test) {
// just like above without checking the annotation
...
$test();
...
}
public function testLogin() {
$this->retryTest(5, function() {
$service = new LoginService();
...
});
}
答案 1 :(得分:7)
不完全是你的问题的答案,但无论如何我会说:你的测试永远不应该包括远程资源(特别是当它们完全不在你手中时(与本地镜像不同))。您应该将连接封装到单独的类中(例如Connection
),并在测试中模拟这些对象并使用静态响应,远程主机将返回。
答案 2 :(得分:3)
您不应该使用模拟对象和灯具,而不是连接到实时服务器,以便来自其他地方的响应不会对您的测试产生影响吗?
您可以使用依赖注入来使用特定的HTTP客户端,该客户端将返回您告诉它的数据和响应代码(取决于您的代码的编写方式)。理想情况下,您的单元测试应该不受外部影响;你应该控制你正在测试的东西,例如,强迫404或500错误应该是你测试的一个独立部分。
不是试图破解非确定性测试,而是通过查看是否可以更改代码以启用模拟和测试夹具来获得更好的服务。
除此之外,您当然可能已经知道,我担心我不知道告诉PHPUnit允许测试失败的方法。这似乎与工具应该做的完全相反。
答案 3 :(得分:1)
我认为没有人支持,有人可以证明我错了,但在这种情况下我会感到惊讶。
我认为你能做的不是在要检索的测试方法中立即断言,而是循环X次并在成功时突破,在循环之外结果将被断言。
您已经考虑过的这种简单方法,有一个缺点,就是为每个测试方法添加更多代码。如果你有很多这样做会增加维护负担。
否则,如果要自动执行更多操作,可以实现PHPUnit_Framework_TestListener,在关联数组中保留失败测试的计数,并与测试运行进行比较。不确定这条路线的可行性,但你可以尝试一下。
答案 4 :(得分:0)
您应该能够创建数据库连接断言,并在您的其他测试中“作为”您的数据库连接实施该测试。在该测试中,您可以根据需要尝试多次,并在X尝试后返回false。