一文掌握python单元测试unittest(二)

 接上篇https://blog.csdn.net/qq_38120851/article/details/141642215

目录

四、参数化测试

1、使用 subTest

2、使用装饰器

3)使用第三方库parameterized

五、跳过测试

1、使用 unittest.skip() 或 unittest.skipIf() 装饰器:

2、使用 setUp() 方法中的断言来跳过整个测试类:

3、在测试方法内部使用 unittest.TestCase.skipTest() 方法:

六、预期失败

七、自定义测试结果类

八、参数化测试进阶,parameterized 库

1、什么是 parameterized?

2、安装 parameterized

3、使用类属性定义参数集:parameterized.expand

4、使用外部文件加载参数集

        1)  使用 CSV 文件加载参数集

        2)  使用yaml加载参数集,推荐使用yaml, 因为yaml结构更清晰,方便维护。

5、使用函数生成参数集

6、使用字典参数集

7、使用param和name_func提供更多的信息,比如参数的名称、描述。

8、使用类级别的参数化

        1)使用属性元组和元组列表

        2)使用字典列表

        3)使用 class_name_func 来动态生成测试类的名字

九、参数化测试进阶,ddt 库

1、通过 pip 安装:

2、data:为测试函数提供多个数据集。

        1)data传参list(同理如果传tuple,即将相应的list换成tuple): 

        2)data传参dict: 

3、unpack:解包

4、file_data:从文件中加载测试数据。每个用例的key会添加到用例名中去。

        1)加载json文件

        2)加载yaml文件

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值