Python基础 - unittest 使用简明教程
概述
unittest 是 Python 标准库中的单元测试框架,深受 Java 的 JUnit 框架影响。它支持测试自动化、共享设置和关闭代码、测试聚合以及测试独立于报告框架。本教程将介绍如何使用 unittest 编写和运行测试。
基本概念
在深入学习之前,先了解几个核心概念:
TestCase: 测试用例的基本类,所有测试类都继承此类
TestSuite: 测试套件,用于组合多个测试用例
TestRunner: 测试运行器,负责执行测试并输出结果
TestFixture: 测试夹具,通过 setUp 和 tearDown 方法管理测试环境
编写测试用例
创建测试类需继承 unittest.TestCase,测试方法必须以 test_ 开头:
import unittest
# 被测函数
def add(a, b):
return a + b
def divide(a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b
# 测试类
class TestMathFunctions(unittest.TestCase):
def test_add(self):
"""测试加法函数"""
self.assertEqual(add(2, 3), 5)
self.assertEqual(add(-1, 1), 0)
def test_divide(self):
"""测试除法函数"""
self.assertEqual(divide(6, 2), 3)
def test_divide_by_zero(self):
"""测试除零异常"""
with self.assertRaises(ValueError):
divide(10, 0)常用断言方法
unittest 提供了丰富的断言方法用于验证测试结果:
class TestAssertions(unittest.TestCase):
def test_assertions(self):
# 相等断言
self.assertEqual(1, 1)
self.assertNotEqual(1, 2)
# 真假断言
self.assertTrue(1 == 1)
self.assertFalse(1 == 2)
# None 断言
self.assertIsNone(None)
self.assertIsNotNone(1)
# 包含断言
self.assertIn(1, [1, 2, 3])
self.assertNotIn(4, [1, 2, 3])
# 类型断言
self.assertIsInstance(1, int)
self.assertNotIsInstance("hello", int)
# 近似相等
self.assertAlmostEqual(0.1 + 0.2, 0.3, places=7)测试夹具 (Test Fixture)
测试夹具用于设置测试环境和清理资源:
class TestWithFixture(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""整个类开始前执行一次"""
print("=== 测试类开始 ===")
@classmethod
def tearDownClass(cls):
"""整个类结束后执行一次"""
print("=== 测试类结束 ===")
def setUp(self):
"""每个测试方法前执行"""
print("--- 测试方法开始 ---")
def tearDown(self):
"""每个测试方法后执行"""
print("--- 测试方法结束 ---")
def test_example(self):
self.assertTrue(True)跳过测试
支持有条件或无条件跳过某些测试:
class TestSkipExample(unittest.TestCase):
@unittest.skip("直接跳过")
def test_skip(self):
self.fail("不会执行")
@unittest.skipIf(1 > 0, "条件为真时跳过")
def test_skip_if(self):
self.fail("条件为真时不会执行")
@unittest.skipUnless(1 < 0, "条件为假时跳过")
def test_skip_unless(self):
self.fail("条件为假时不会执行")
@unittest.expectedFailure
def test_expected_failure(self):
self.assertEqual(1, 2) # 预期会失败参数化测试
通过第三方库 parameterized 实现参数化测试:
pip install parameterizedfrom parameterized import parameterized
class TestParameterized(unittest.TestCase):
@parameterized.expand([
(1, 1, 2),
(2, 3, 5),
(-1, -1, -2),
(0, 0, 0)
])
def test_add_parameterized(self, a, b, expected):
self.assertEqual(add(a, b), expected)测试套件
测试套件允许将多个测试用例组合在一起运行:
def suite():
suite = unittest.TestSuite()
suite.addTest(TestMathFunctions('test_add'))
suite.addTest(TestMathFunctions('test_divide'))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())运行测试
提供多种运行测试的方式:
方法1: 直接运行
if __name__ == '__main__':
unittest.main()方法2: 命令行运行
# 运行所有测试
python -m unittest
# 运行指定模块
python -m unittest test_module
# 运行指定类
python -m unittest test_module.TestClass
# 运行指定方法
python -m unittest test_module.TestClass.test_method
# 发现并运行所有测试
python -m unittest discover
# 发现指定目录的测试
python -m unittest discover -s project/tests
# 详细输出
python -m unittest -v
# 遇到第一个失败就停止
python -m unittest -f
## 测试组织建议
合理的测试目录结构有助于维护测试代码:
```text
project/
├── src/
│ └── mymodule.py
└── tests/
├── __init__.py
├── test_module1.py
├── test_module2.py
└── integration/
└── test_integration.py总结
unittest 提供了完整的测试解决方案,从简单的单元测试到复杂的集成测试。通过合理组织测试代码和使用各种测试特性,可以构建健壮、可维护的测试套件,确保代码质量。