我有一个python函数,如果传递坏数据会被无限循环捕获。我想写一个单元测试来确认它优雅地处理坏参数。问题当然是,如果它没有检测到错误的参数,它就不会返回。
使用线程为这类事件编写测试是否可以接受?
import threading, unittest
import mymodule
class CallSuspectFunctionThread(threading.Thread):
def __init__(self, func, *args):
self.func = func
self.args = args
super(CallSuspectFunctionThread, self).__init__()
def run(self):
self.func(*self.args)
class TestNoInfiniteLoop(unittest.TestCase):
def test_no_infinite_loop(self):
myobj = mymodule.MyObject()
bad_args = (-1,0)
test_thread = CallSuspectFunctionThread(mybj.func_to_test, *bad_args)
test_thread.daemon = True
test_thread.start()
# fail if func doesn't return after 8 seconds
for i in range(32):
test_thread.join(0.25)
if not test_thread.is_alive():
return
self.fail("function doesn't return")
我看到的唯一问题是,如果测试失败,我会遇到这个额外的线程,可能会消耗cpu和内存资源,而其余的测试都会被执行。另一方面,我已经修复了代码,回归的可能性非常小,所以我不知道是否包括测试是否重要。
答案 0 :(得分:12)
您可以添加超时装饰器。将测试用例的逻辑与超时机制实现分开是很好的。这将使您的代码更易读,更易于维护。
答案 1 :(得分:1)
我会添加测试来测试无限循环,因为如果它在测试期间挂起,那么至少你在生产之前就已经发现了这个bug。如果它发生的可能性很小(如你所说),那么我不会担心复杂的测试,但我仍然会测试代码。
答案 2 :(得分:0)
对这种情况进行测试是一个好主意。在测试代码时,您可以对其质量更有信心。
至于您为测试函数而创建的主题,这里是two ways to kill a thread in python。由于您位于具有无限循环的函数内部,因此您必须使用第二种方法来摆脱循环。
答案 3 :(得分:0)
实际上你不必抓住它。只要它在您的测试中,您一定会注意到它是否出错。
答案 4 :(得分:0)
你无法测试这个。如果另一个线程只是“慢”或更糟“活锁”(即等待共享资源)怎么办?你所做的任何假设都可能与现实相悖。
你不能耸耸肩说:“它总是习惯在1.5秒内终止,但现在似乎要花一点时间。我会尝试2秒钟,看看它是否通过了。”那是不可接受的。
您必须始终证明所有循环的终止。所有循环。
任何不足只是一种设计,它是如此糟糕,以至于它永远不会看到光明。
如果你无法阻止和无限循环,你就没有完成设计。
这不是可以测试的东西。
答案 5 :(得分:0)
也许在你的情况下你可以解决它,因为接受的答案说。对你有益。 然而,当你无法统治“永远挂起”的情况时,有些情况(对于集成和冒烟测试,而不是单元测试)。对于这些情况,我喜欢this timeout解决方案。