You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何第二次调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 08:38:49