接上篇:https://blog.csdn.net/qq_38120851/article/details/141642215
目录
1、使用 unittest.skip() 或 unittest.skipIf() 装饰器:
3、在测试方法内部使用 unittest.TestCase.skipTest() 方法:
3、使用类属性定义参数集:parameterized.expand
2) 使用yaml加载参数集,推荐使用yaml, 因为yaml结构更清晰,方便维护。
7、使用param和name_func提供更多的信息,比如参数的名称、描述。
3)使用 class_name_func 来动态生成测试类的名字
1)data传参list(同理如果传tuple,即将相应的list换成tuple):
4、file_data:从文件中加载测试数据。每个用例的key会添加到用例名中去。
5、named_data:为每组测试数据提供一个名称,这有助于识别测试案例。
四、参数化测试
参数化测试是一种常见的需求,特别是在需要针对一组数据多次运行相同的测试逻辑时。unittest
本身并没有直接支持参数化测试的功能,但是可以通过一些技巧来实现这一点。
通常用第三方库pytest或parameterized来进行参数化测试。
1、使用 subTest
unittest
提供了 subTest
方法来实现参数化测试,可以在测试方法内部使用它来创建子测试,每个子测试都有一个特定的上下文。即结合循环来间接实现参数化测试。
import unittest
class TestMultiplication(unittest.TestCase):
def test_multiply(self):
cases = [
(2, 3, 6),
(2, -3, -6),
(-2, -3, 6)
]
for x, y, expected in cases:
with self.subTest(x=x, y=y):
self.assertEqual(x * y, expected)
print(f'Test passed for x={x}, y={y}, expected={expected}')
if __name__ == "__main__":
unittest.main()
2、使用装饰器
缺点是实际是运行了3个用例,但是控制台上输出是Ran 1 tests in 0.000s,统计测试输出报告时比较麻烦。
import unittest
class parameterized(object):
@staticmethod
def expand(argvalues):
def decorator(func):
def wrapper(*args):
for arg in argvalues:
func(*(args + arg))
return wrapper
return decorator
class TestMathFunctions(unittest.TestCase):
@parameterized.expand([
(2, 3, 5),
(3, 4, 7),
(1, 9, 10)
])
def test_add(self, a, b, expected):
result = a + b
self.assertEqual(result, expected)
print("Test add with a={}, b={}, expected={}".format(a, b, expected))
if __name__ == '__main__':
unittest.main()
但是控制台上输出是Ran 1 test in 0.000s
3)使用第三方库parameterized
import unittest
from parameterized import parameterized
class TestMathFunctions(unittest.TestCase):
@parameterized.expand([
(1, 2, 3),
(4, 5, 9),
(10, -2, 8)
])
def test_add(self, a, b, expected):
result = a + b
self.assertEqual(result, expected)
if __name__ == "__main__":
unittest.main()
控制台上输出是Ran 3 tests in 0.000s
五、跳过测试
1、使用 unittest.skip()
或 unittest.skipIf()
装饰器:
unittest.skip(reason)
:可以无条件地跳过一个测试方法,并给出跳过的理由。unittest.skipIf(condition, reason)
:只有当给定的条件为True
时才会跳过测试方法。
import unittest
class TestSkipExample(unittest.TestCase):
@unittest.skip("无条件跳过这个测试")
def test_always_skipped(self):
self.fail("应该不会执行到这里")
@unittest.skipIf(True, "条件为真时跳过这个测试")
def test_skipped_if_true(self):
self.fail("条件为真时不应该执行到这里")
@unittest.skipIf(False, "条件为假时跳过这个测试")
def test_not_skipped_if_false(self):
self.assertTrue(True) # 这个测试将会被执行
if __name__ == '__main__':
unittest.main()
2、使用 setUp()
方法中的断言来跳过整个测试类:
- 如果
setUp()
方法中抛出异常(例如通过assert
),那么整个测试类将不会被执行。
import unittest
class TestSetupSkipExample(unittest.TestCase):
def setUp(self):
self.skipTest("setUp 中的断言失败,跳过整个测试类") # 这行代码将导致整个测试类被跳过
def test_example_one(self):
self.assertTrue(True)
def test_example_two(self):
self.assertTrue(True)
if __name__ == '__main__':
unittest.main()
3、在测试方法内部使用 unittest.TestCase.skipTest()
方法:
- 如果在一个测试方法内部想要跳过后续的测试步骤,可以使用
self.skipTest(reason)
。
import unittest
class TestSkipInMethodExample(unittest.TestCase):
def test_example(self):
self.skipTest("测试方法内部决定跳过")
self.assertTrue(False) # 这行代码不会被执行
def test_example_2(self):
self.assertTrue(True) # 这行代码不会被执行
if __name__ == '__main__':
unittest.main()
六、预期失败
使用 expectedFailure
装饰器来标记那些预期会失败的测试用例。这在开发过程中非常有用,特别是当正在重构代码或逐步改进现有功能时。这样,可以跟踪哪些测试在当前状态下应该是失败的,直到它们最终通过为止。
import unittest
class TestExpectedFailures(unittest.TestCase):
def test_known_failure(self):
""" 这个测试应该失败,因为我们还没有修复这个 bug。 """
self.assertEqual(1, 2) # 这个断言应该失败
@unittest.expectedFailure
def test_known_failure_with_decorator(self):
""" 使用装饰器标记已知的失败测试。 """
self.assertEqual(1, 2) # 这个断言应该失败
def test_known_failure_without_decorator(self):
""" 这个测试应该失败,但我们没有使用装饰器标记。 """
self.assertEqual(1, 2) # 这个断言应该失败
if __name__ == "__main__":
unittest.main()
七、自定义测试结果类
通过继承 unittest.TextTestResult
类来自定义测试结果的处理方式。这样做可以增加更多的定制功能,比如记录额外的信息、更改输出格式等。
import unittest
import sys
class CustomTestResult(unittest.TextTestResult):
"""自定义测试结果类,扩展了unittest.TextTestResult以添加额外的测试结果输出功能."""
def __init__(self, stream, descriptions, verbosity):
"""初始化自定义测试结果,设置输出流、描述和详细程度."""
super().__init__(stream, descriptions, verbosity)
def startTest(self, test):
"""在测试开始时调用,打印开始测试的信息."""
super().startTest(test)
print(f"Starting test: {test}")
def addSuccess(self, test):
"""在测试成功时调用,打印测试通过的信息."""
super().addSuccess(test)
print(f"Test {test} passed.")
def addFailure(self, test, err):
"""在测试失败时调用,打印测试失败的信息及错误."""
super().addFailure(test, err)
print(f"Test {test} failed: {err}")
def addError(self, test, err):
"""在测试出错时调用,打印测试出错的信息及错误."""
super().addError(test, err)
print(f"Test {test} err