Python unittest框架 实用函数与特性
assertRaisesRegex 用于验证抛出的异常是否包含预期的消息。
一、unittest 基础介绍
unittest 模块提供了一种结构化的方式来编写测试用例。测试用例继承自 unittest.TestCase 类,并通过一系列的测试方法(以 test_ 开头的方法)来组织。
二、测试套件 (TestSuite)
unittest.TestSuite 是一个容器对象,可以容纳多个测试用例,这样就可以批量执行一组测试用例。
创建测试套件
-
import unittest -
class TestStringMethods(unittest.TestCase): -
def test_upper(self): -
self.assertEqual('foo'.upper(), 'FOO') -
class TestNumberMethods(unittest.TestCase): -
def test_add(self): -
self.assertEqual(1 + 2, 3) -
def suite(): -
suite = unittest.TestSuite() -
suite.addTest(TestStringMethods('test_upper')) -
suite.addTest(TestNumberMethods('test_add')) -
return suite -
if __name__ == '__main__': -
runner = unittest.TextTestRunner() -
runner.run(suite()) -
# 输出: -
# ..... -
# ---------------------------------------------------------------------- -
# Ran 2 tests in 0.000s -
# -
# OK
unittest.TestLoader 提供了自动发现和加载测试用例的方法。
使用测试加载器自动发现测试
-
import unittest -
class TestStringMethods(unittest.TestCase): -
def test_upper(self): -
self.assertEqual('foo'.upper(), 'FOO') -
class TestNumberMethods(unittest.TestCase): -
def test_add(self): -
self.assertEqual(1 + 2, 3) -
if __name__ == '__main__': -
loader = unittest.TestLoader() -
tests = loader.discover(start_dir='.', pattern='test*.py') -
runner = unittest.TextTestRunner() -
runner.run(tests) -
# 输出: -
# ..... -
# ---------------------------------------------------------------------- -
# Ran 2 tests in 0.000s -
# -
# OK
unittest 默认使用 TextTestResult 来处理测试结果。我们可以通过继承 TextTestResult 来定制输出格式。
定制测试结果输出
-
import unittest -
class CustomTestResult(unittest.TextTestResult): -
def addSuccess(self, test): -
super().addSuccess(test) -
print(f"测试成功: {test}") -
class TestStringMethods(unittest.TestCase): -
def test_upper(self): -
self.assertEqual('foo'.upper(), 'FOO') -
if __name__ == '__main__': -
loader = unittest.TestLoader() -
tests = loader.loadTestsFromTestCase(TestStringMethods) -
runner = unittest.TextTestRunner(resultclass=CustomTestResult) -
runner.run(tests) -
# 输出: -
# 测试成功: <__main__.TestStringMethods testMethod=test_upper> -
# ..... -
# ---------------------------------------------------------------------- -
# Ran 1 test in 0.000s -
# -
# OK
unittest 提供了 skip 和 skipIf 装饰器来跳过某些测试用例。
使用 skip 装饰器跳过测试
-
import unittest -
class TestStringMethods(unittest.TestCase): -
@unittest.skip("暂时跳过此测试") -
def test_upper(self): -
self.assertEqual('foo'.upper(), 'FOO') -
def test_split(self): -
s = 'hello world' -
self.assertEqual(s.split(), ['hello', 'world']) -
if __name__ == '__main__': -
unittest.main() -
# 输出: -
# ..... -
# ---------------------------------------------------------------------- -
# Ran 1 test in 0.000s -
# -
# OK
使用 skipIf 装饰器条件性跳过测试
-
import unittest -
class TestStringMethods(unittest.TestCase): -
@unittest.skipIf(True, "当条件为真时跳过此测试") -
def test_upper(self): -
self.assertEqual('foo'.upper(), 'FOO') -
def test_split(self): -
s = 'hello world' -
self.assertEqual(s.split(), ['hello', 'world']) -
if __name__ == '__main__': -
unittest.main() -
# 输出: -
# ..... -
# ---------------------------------------------------------------------- -
# Ran 1 test in 0.000s -
# -
# OK
虽然 unittest 本身不支持测试重试,但可以通过装饰器或第三方库来实现。
使用装饰器实现测试重试
-
import unittest -
import time -
def retry(max_attempts=3, delay=1): -
def decorator(func): -
def wrapper(*args, **kwargs): -
attempts = 0 -
while attempts < max_attempts: -
try: -
return func(*args, **kwargs) -
except Exception as e: -
attempts += 1 -
if attempts >= max_attempts: -
raise -
time.sleep(delay) -
return wrapper -
return decorator -
class TestStringMethods(unittest.TestCase): -
@retry(max_attempts=3, delay=1) -
def test_upper(self): -
self.assertEqual('foo'.upper(), 'FOO') -
if __name__ == '__main__': -
unittest.main() -
# 输出: -
# ..... -
# ---------------------------------------------------------------------- -
# Ran 1 test in 0.000s -
# -
# OK
默认情况下,unittest 会按照定义的顺序执行测试用例,但如果需要改变顺序,可以通过其他方式实现。
改变测试用例的执行顺序
-
import unittest -
class TestStringMethods(unittest.TestCase): -
def test_upper(self): -
self.assertEqual('foo'.upper(), 'FOO') -
def test_split(self): -
s = 'hello world' -
self.assertEqual(s.split(), ['hello', 'world']) -
def test_isupper(self): -
self.assertTrue('FOO'.isupper()) -
if __name__ == '__main__': -
loader = unittest.TestLoader() -
loader.sortTestMethodsUsing = lambda _, x, y: -1 if x > y else 1 -
tests = loader.loadTestsFromTestCase(TestStringMethods) -
runner = unittest.TextTestRunner() -
runner.run(tests) -
# 输出: -
# ..... -
# ---------------------------------------------------------------------- -
# Ran 3 tests in 0.000s -
# -
# OK
八、测试用例的标签 (tags)
虽然 unittest 本身不直接支持测试用例的标签功能,但可以通过自定义测试加载器来实现。
使用自定义测试加载器添加标签
-
import unittest -
class TestStringMethods(unittest.TestCase): -
def test_upper(self): -
self.assertEqual('foo'.upper(), 'FOO') -
def test_split(self): -
s = 'hello world' -
self.assertEqual(s.split(), ['hello', 'world']) -
def load_tests(loader, tests, pattern): -
suite = unittest.TestSuite() -
for test_case in tests: -
if hasattr(test_case, '_testMethodName'): -
if 'slow' in getattr(test_case, '_testMethodName'): -
continue -
suite.addTest(test_case) -
return suite -
if __name__ == '__main__': -
loader = unittest.TestLoader() -
tests = loader.loadTestsFromTestCase(TestStringMethods) -
tests = load_tests(loader, tests, pattern='test*') -
runner = unittest.TextTestRunner() -
runner.run(tests) -
# 输出: -
# ..... -
# ---------------------------------------------------------------------- -
# Ran 2 tests in 0.000s -
# -
# OK
九、使用 setUpClass 和 tearDownClass
setUpClass 和 tearDownClass 方法会在所有测试方法之前和之后分别被调用一次。
使用 setUpClass 和 tearDownClass
-
import unittest -
class TestStringMethods(unittest.TestCase): -
@classmethod -
def setUpClass(cls): -
print("设置测试环境") -
@classmethod -
def tearDownClass(cls): -
print("清理测试环境") -
def test_upper(self): -
self.assertEqual('foo'.upper(), 'FOO') -
def test_split(self): -
s = 'hello world' -
self.assertEqual(s.split(), ['hello', 'world']) -
if __name__ == '__main__': -
unittest.main() -
# 输出: -
# 设置测试环境 -
# ..... -
# 清理测试环境 -
# ---------------------------------------------------------------------- -
# Ran 2 tests in 0.000s -
# -
# OK
十、使用 assertRaisesRegex 验证异常消息
assertRaisesRegex 用于验证抛出的异常是否包含预期的消息。
使用 assertRaisesRegex
-
import unittest -
class TestStringMethods(unittest.TestCase): -
def test_split(self): -
s = 'hello world' -
with self.assertRaisesRegex(ValueError, "empty separator"): -
s.split('') -
if __name__ == '__main__': -
unittest.main() -
# 输出: -
# ..... -
# ---------------------------------------------------------------------- -
# Ran 1 test in 0.000s -
# -
# OK
感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取

更多推荐


所有评论(0)