Python unittest框架 实用函数与特性

2067 篇文章 51 订阅
1266 篇文章 21 订阅

一、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

三、测试加载器 (TestLoader)

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

四、测试结果处理器 (TextTestResult)

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

五、测试用例的跳过 (skip)

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

六、测试用例的重试 (retry)

虽然 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

七、测试用例的顺序 (order)

默认情况下,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

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】

在这里插入图片描述

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值