为何第二次调用unittest.discover()会触发ImportError?如何解决?
问题原因
问题出在unittest.TestLoader.discover()的默认行为上:
- 当调用
discover('test_cases/x', pattern='__init__.py')时,top_level_dir参数默认被设为start_dir(即test_cases/x),该目录会被添加到sys.path的开头。 - 此时导入
__init__.py时,模块名被注册为__init__并存入sys.modules缓存。 - 第二次调用
discover('test_cases/y', ...)时,同样会把test_cases/y加入sys.path,尝试导入__init__.py时,发现sys.modules中已存在同名模块,且路径来自test_cases/x,与当前预期的test_cases/y不符,因此触发ImportError。
修复方案
方案1:指定top_level_dir参数
明确告诉discover测试的顶级目录(即包含test_cases的根目录),让模块以完整包路径注册(如test_cases.x、test_cases.y),避免同名冲突:
import unittest import os if __name__ == "__main__": # 获取当前脚本所在的根目录 top_level_dir = os.path.dirname(os.path.abspath(__file__)) x_test_suite = unittest.TestLoader().discover( start_dir='test_cases/x', pattern='__init__.py', top_level_dir=top_level_dir ) unittest.TextTestRunner(verbosity=1).run(x_test_suite) y_test_suite = unittest.TestLoader().discover( start_dir='test_cases/y', pattern='__init__.py', top_level_dir=top_level_dir ) unittest.TextTestRunner(verbosity=1).run(y_test_suite)
方案2:手动导入子包构建测试套件
跳过discover的自动路径处理,直接导入测试子包,利用load_tests机制构建套件:
import unittest from test_cases import x, y if __name__ == "__main__": loader = unittest.TestLoader() # 加载x包的测试套件 x_suite = loader.loadTestsFromModule(x) unittest.TextTestRunner(verbosity=1).run(x_suite) # 加载y包的测试套件 y_suite = loader.loadTestsFromModule(y) unittest.TextTestRunner(verbosity=1).run(y_suite)
额外注意事项
- 除非你需要通过
__init__.py的load_tests组织测试,否则不建议将pattern设为__init__.py,使用默认的test*.py模式更符合规范。 - 若不需要末尾的
unittest.main(),可直接移除,避免重复触发测试发现流程。
内容的提问来源于stack exchange,提问作者isak bob
相关产品推荐
相关产品推荐

