在不修改的情况下测试Python线程代码?
假设我有一段代码,它是一个长时间运行的线程,用来不断检查事件并触发其他事件(在我的例子中,是通过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为止,我找不到任何方法来强制它抛出异常或者杀掉这个线程,这样我就可以从头开始运行,而不需要改变我正在测试的代码。一旦我调用了测试中的函数,我就失去了从线程中检查任何标志的能力。
我知道这真的不是测试应该工作的方式,集成测试的价值有限等等,但我希望能通过逐步展示测试和良好设计的价值,来让我的朋友明白,而不是一次性彻底重构他的软件。
2 个回答
4
最后一个大问题是,测试的代码是设计成可以一直运行的,直到按下Ctrl-C,我看不出有什么办法可以强制它抛出异常或者结束这个线程。
测试驱动开发的重点在于重新思考你的设计,使其能够被测试。
虽然一直循环运行在生产环境中看起来没问题,但实际上是无法进行测试的。
所以要让这个循环能够结束。这样不会对生产环境造成影响,反而会提高测试的可行性。
那种“设计成可以一直运行”的方式并不适合测试。因此,要调整设计,使其能够被测试。
0
我觉得我找到了一个解决办法,正好符合我的需求:与其使用线程,不如用一个单独的进程。
我可以写一个简单的Python小程序来模拟一些功能,并以可控的方式运行代码。然后,我可以写实际的测试,让我的小程序在每个测试中作为一个子进程运行,测试结束后再把它杀掉。这个测试进程可以通过stdio
或者一个套接字与小程序进行互动。