Python unittest的test runner是否在独立线程运行?执行顺序如何?
Python unittest 执行顺序与线程机制说明
Test Runner 的线程归属
随Python标准库提供的默认unittest.TextTestRunner(以及unittest.main()入口)运行在调用它的主线程中,不存在内置的独立线程隔离:
- 所有测试用例收集、前置钩子执行、测试方法运行、后置钩子清理的全流程,都和启动runner的执行线程绑定
- 框架本身不会主动切换执行线程,只有手动编写代码将runner启动逻辑封装到自定义的Thread实例中时,runner才会运行在独立线程中。
完整默认执行链路
框架启动后的执行顺序是固定的,不存在随机调度,全流程按以下步骤推进:
- 测试收集阶段(所有前置钩子执行前完成)
- 扫描指定路径下所有匹配
test_*.py规则的测试文件,加载所有继承自unittest.TestCase的测试类 - 收集每个测试类下所有以
test_为前缀的方法,按照方法名的ASCII编码顺序完成排序,这个排序结果会贯穿整个测试执行流程,不会按照代码书写时的先后顺序调度。
- 扫描指定路径下所有匹配
- 测试类级别的前置执行
- 对每个待执行的测试类,首先调用类级别的一次性前置钩子
setUpClass(),整个类的所有用例执行期间该方法仅运行一次。
- 对每个待执行的测试类,首先调用类级别的一次性前置钩子
- 单条测试用例的循环执行
按照之前排好序的用例列表,逐次对每个test_*方法执行完整的执行流程:- 先调用单条用例级别的前置钩子
setUp(),完成当前用例的专属初始化逻辑 - 若
setUp()执行过程中抛出任何异常,会直接终止当前用例的后续流程,跳过对应的test_*方法,直接进入当前用例的后置清理环节 - 若
setUp()执行完成无异常,当前顺序下的第一个(以及后续每个)test_*方法会紧随setUp()执行,中间不存在额外的可干预业务环节 - 待
test_*方法执行完成(无论成功、失败还是报错),调用单条用例的后置钩子tearDown()完成清理
- 先调用单条用例级别的前置钩子
- 测试类级别的后置执行
- 类下所有用例全部执行完成后,调用类级别的一次性后置钩子
tearDownClass(),整个类的所有用例执行期间该方法仅运行一次。
- 类下所有用例全部执行完成后,调用类级别的一次性后置钩子
打破默认顺序的特殊场景
不存在在setUp()和首个test_*方法之间插入额外流程的默认逻辑,仅以下情况会打断原有的执行顺序:
setUp()执行抛出任何类型的异常,直接跳过当前绑定的test_*方法- 测试类、测试方法、setUp方法被加上跳过装饰器(如
@unittest.skip),会在进入对应环节前直接标记用例为跳过,不触发后续流程 - 测试收集阶段出现导入失败、类定义错误,会直接标记对应测试实体为加载失败,不会触发任何前置钩子逻辑。
多线程测试场景注意事项
- 默认runner是串行运行在主线程,没有内置的并行执行能力,测试过程中如果被测应用启动了独立的业务子线程,需要主动做线程同步(比如调用子线程的
join()方法、基于事件机制等待子线程执行完成),避免测试流程已经走到清理环节、业务子线程仍在修改全局测试状态,导致后续用例出现非预期失败 - 不要依赖runner所在的主线程做业务线程的状态判断,子线程的执行节奏不受unittest框架的调度控制。
内容的提问来源于stack exchange,提问作者Mitch Ostler
相关产品推荐
相关产品推荐

