我正在使用Thrift编写服务,需要应用一些测试以确保它按预期运行/响应。要做到这一点,最稳健的方法似乎是使用该unittest
模块。
我想直接在单元测试的setUp
方法中以“测试”模式启动服务(在特定的“测试”端口上启动,使用“测试”数据等),但此时调用serve()
块等待连接。
启动服务的最佳方法是什么,以便可以执行测试并使用该tearDown
方法干净地关闭服务?
我正在使用Thrift编写服务,需要应用一些测试以确保它按预期运行/响应。要做到这一点,最稳健的方法似乎是使用该unittest
模块。
我想直接在单元测试的setUp
方法中以“测试”模式启动服务(在特定的“测试”端口上启动,使用“测试”数据等),但此时调用serve()
块等待连接。
启动服务的最佳方法是什么,以便可以执行测试并使用该tearDown
方法干净地关闭服务?
提供的“完全隔离”unittest
非常适用于单元测试(它的设计目的),但不一定适用于集成测试——我看到重用unittest
这些测试的吸引力,我自己这样做是为了利用我们拥有的特殊测试运行器&c周围,但是,意识到它是一种适合unittest
用于集成测试的力量,我尝试通过编码而不是编写单元测试来进行补偿。
当我必须在集成测试中生成服务器时,我倾向于在模块的开头,在一个单独的进程中进行生成——通过subprocess
,或者通过其他适合你的安装的方式,如果你想在一个单独的环境中运行它节点或其他任何东西 - 并向atexit注册终止代码,当我的测试模块全部完成时,该代码将向该服务器发送终止请求。这不像单元测试所要求的那样“完全分离”,但我发现它对于集成测试来说已经足够好了,并且分摊了启动和初始化服务器的开销,这在多个测试中确实可能非常高。
即使您热衷于使用setUp
and tearDown
,我仍然建议您使用单独的进程(和单独的节点,如果您在“持续构建农场”等中有很多人的话)。正如@Ned 的回答所暗示的那样,在同一进程中使用不同的线程让我觉得有风险——可能很容易在服务器和测试之间产生不需要的交互,隐藏一些错误或导致其他错误。
如果我理解正确,您不仅要在同一进程上运行服务器,而且还要在与测试相同的线程中运行服务器,这对我来说绝对是个坏主意-当然它会阻止一切,除非服务器编码确实非常特别!-)
您可以创建一个上下文管理器来在服务器在后台运行时启动您的测试。
if __name__ == '__main__':
with background_server():
print('Server loaded, launching the tests...')
unittest.main(exit=False)
我用于的代码background_server
:
@contextlib.contextmanager
def background_server():
# Launching the server
pid_server = os.fork()
if not pid_server: # Child code
launch_server() # Blocking call (until signal.SIGINT)
print('Interuption detected, server closed...')
sys.exit() # Closing the process
# HACK: Wait for the server to be launched
while True:
try:
requests.get("http://localhost:5000/", timeout=0.5)
break
except requests.exceptions.ConnectionError:
pass
time.sleep(0.3)
try:
yield
finally:
# Closing the server
os.kill(pid_server, signal.SIGINT)
如果serve()
阻塞,那么你最好的选择是产生一个线程setUp
来调用serve()
。然后你必须弄清楚如何在tearDown
方法中停止 Thrift。