unittest错误重跑与测试用例跳过机制
错误重跑与测试用例跳过机制
在 unittest 框架中,错误重跑机制和测试用例跳过机制是两个重要的功能,它们分别用于处理不稳定测试和选择性执行测试。以下是对这两个机制的详细介绍:
6. 错误重跑机制
错误重跑机制允许在测试用例失败时自动重试,有助于过滤因环境波动导致的偶发失败(Flaky Tests)。unittest 原生不支持重跑,但可以通过以下方式实现:
6.1 自定义重试装饰器
通过装饰器为单个测试方法添加重试逻辑:
import unittest import functools def retry(tries=3, exceptions=(AssertionError,)): """重试装饰器,用于测试方法""" def decorator(func): @functools.wraps(func) def wrapper(self, *args, **kwargs): attempt = 0 while attempt < tries: try: return func(self, *args, **kwargs) except exceptions as e: attempt += 1 if attempt == tries: raise print(f"测试失败,重试 ({attempt}/{tries}): {e}") return wrapper return decorator class TestExample(unittest.TestCase): @retry(tries=3) # 失败时重试3次 def test_flaky(self): import random self.assertTrue(random.choice([True, False])) # 模拟不稳定测试 if __name__ == '__main__': unittest.main() |
6.2 自定义 TestCase 基类
通过继承 unittest.TestCase 并重写 run() 方法,为所有测试用例添加重试逻辑:
import unittest class RetryTestCase(unittest.TestCase): max_retries = 3 # 全局重试次数 def run(self, result=None): retry_count = 0 success = False
while not success and retry_count <= self.max_retries: # 重置结果对象 if result: result._mirrorOutput = False # 避免重复输出
# 执行测试 super().run(result)
# 检查是否需要重试 if result.failures or result.errors: retry_count += 1 print(f"测试失败,重试 ({retry_count}/{self.max_retries})") # 清空当前失败记录 result.failures = [] result.errors = [] else: success = True class TestMath(RetryTestCase): def test_flaky(self): import random self.assertEqual(random.randint(1, 10) % 2, 0) # 50% 概率失败 |
6.3 使用第三方库(如 XTestRunner)
XTestRunner 提供了更完善的重跑功能,支持生成包含重跑记录的 HTML 报告:
import unittest from XTestRunner import HTMLTestRunner class TestExample(unittest.TestCase): def test_flaky(self): import random self.assertTrue(random.choice([True, False])) if __name__ == '__main__': suite = unittest.TestSuite() suite.addTest(TestExample("test_flaky"))
with open('report.html', 'wb') as f: runner = HTMLTestRunner( stream=f, title="测试报告", rerun=3 # 失败重试3次 ) runner.run(suite) |
7. Case 跳过机制
unittest 提供了内置的跳过机制,允许根据条件或版本选择性执行测试用例。
7.1 无条件跳过
使用 @unittest.skip(reason) 装饰器直接跳过测试:
import unittest class TestFeatures(unittest.TestCase): @unittest.skip("该功能尚未实现") def test_feature_x(self): pass # 此测试会被跳过
def test_feature_y(self): self.assertTrue(True) |
7.2 条件性跳过
使用 @unittest.skipIf(condition, reason) 或 @unittest.skipUnless(condition, reason):
import unittest import sys class TestPlatform(unittest.TestCase): @unittest.skipIf(sys.platform != 'linux', "仅在 Linux 上运行") def test_linux_feature(self): pass
@unittest.skipUnless(sys.version_info >= (3, 8), "需要 Python 3.8+") def test_python38_feature(self): pass |
7.3 动态跳过
在测试方法中使用 self.skipTest(reason) 动态跳过:
import unittest import requests class TestAPI(unittest.TestCase): def test_external_api(self): try: response = requests.get("https://api.example.com") except requests.ConnectionError: self.skipTest("无法连接到外部 API")
self.assertEqual(response.status_code, 200) |
7.4 跳过整个测试类
在类定义前添加装饰器:
import unittest @unittest.skip("模块重构中,暂不执行测试") class TestLegacyCode(unittest.TestCase): def test_case1(self): pass # 整个类的测试都会被跳过 |
总结
- 错误重跑机制:用于处理不稳定测试,通过自定义装饰器、基类或第三方库实现。
- Case 跳过机制:用于选择性执行测试,通过 @skip、@skipIf、@skipUnless 装饰器或 self.skipTest() 方法实现。
这两种机制结合使用可以显著提高测试效率,减少无效测试的干扰,让测试聚焦于真正需要验证的功能。