让我们说我有一大堆代码,这些代码是一个长期运行的执行线程,用于轮询事件并触发其他事件(在我的情况下,使用XMLRPC调用)。它需要重构为干净的对象,因此它可以进行单元测试,但与此同时我想在一些集成测试中捕获它的一些当前行为,将其视为黑盒子。例如:
# long-lived code
import xmlrpclib
s = xmlrpclib.ServerProxy('http://XXX:yyyy')
def do_stuff():
while True:
...
if s.xyz():
s.do_thing(...)
_
# test code
import threading, time
# stub out xmlrpclib
def run_do_stuff():
other_code.do_stuff()
def setUp():
t = threading.Thread(target=run_do_stuff)
t.setDaemon(True)
def tearDown():
# somehow kill t
t.join()
def test1():
t.start()
time.sleep(5)
assert some_XMLRPC_side_effects
最后一个大问题是被测试的代码是设计为永久运行,直到Ctrl-C,我没有看到任何方法强制它引发异常或以其他方式杀死线程所以我可以从头开始,不改变我测试的代码。一旦我调用被测函数,我就失去了从我的线程中轮询任何标志的能力。
我知道这真的不是测试设计如何工作,集成测试价值有限等等,但我希望能够展示测试和良好设计的价值朋友通过轻轻地努力,而不是一次性完全重新设计他的软件。
答案 0 :(得分:4)
最后一个大问题是被测代码被设计为永远运行,直到Ctrl-C,我没有看到任何方法强制它引发异常或以其他方式终止线程
测试驱动开发的目的是重新考虑您的设计,使其 可测试。
永远循环 - 虽然看似很好的生产用途 - 是不可测试的。
所以让循环终止。它不会伤害生产。它将提高可测试性。
“设计为永远运行”不是为可测试性而设计的。因此,将设计修复为可测试。
答案 1 :(得分:0)
我认为我找到了一个能够满足我所需要的解决方案:不使用线程,而是使用单独的流程。
我可以编写一个小的python存根来进行模拟并以受控方式运行代码。然后我可以编写实际的测试来在每个测试的子进程中运行我的存根,并在每个测试完成后终止它。测试过程可以通过stdio
或套接字与存根进行交互。