前言
下面是一个关于 Python 的 unittest
单元测试框架的 详细教程,适合初学者逐步入门,也包含了一些进阶用法,帮助你在项目中高效使用 unittest
。
官方文档地址:https://docs.python.org/zh-cn/3.13/library/unittest.html
📝 目录
- 什么是单元测试?
- 为什么使用
unittest
? - 基本使用方式
- 断言方法
- 测试用例组织
- 测试夹具:
setUp()
和tearDown()
- 测试套件与运行方式
- Mock 模拟对象(高级)
- 实战示例
- 小结
1️⃣ 什么是单元测试?
单元测试(Unit Test) 是指对软件中的最小可测试单元进行验证的测试活动。通常指的是函数或类的方法。
2️⃣ 为什么使用 unittest
?
Python 的 unittest
是标准库内置的测试框架,具有以下优点:
- 类似于 Java 的 JUnit,功能全面
- 无需额外安装
- 支持测试夹具、测试套件、断言等
- 可以集成到 CI/CD 工具中
3️⃣ 基本使用方式
# calculator.py
def add(x, y):
return x + y
def divide(x, y):
return x / y
# test_calculator.py
import unittest
from calculator import add, divide
class TestCalculator(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(10, 2), 5)
with self.assertRaises(ZeroDivisionError):
divide(10, 0)
if __name__ == '__main__':
unittest.main()
🟡 运行方法:
python test_calculator.py
输出:
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
4️⃣ 常用断言方法
方法 | 用途 |
---|---|
assertEqual(a, b) |
断言 a == b |
assertNotEqual(a, b) |
断言 a != b |
assertTrue(x) |
断言 x 为 True |
assertFalse(x) |
断言 x 为 False |
assertIs(a, b) |
断言 a is b |
assertIsNone(x) |
断言 x is None |
assertIn(a, b) |
断言 a in b |
assertRaises(Exception) |
断言抛出异常 |
5️⃣ 测试用例组织结构
建议使用以下结构组织测试文件:
project/
├── calculator.py
└── tests/
└── test_calculator.py
可以批量运行:
python -m unittest discover -s tests
6️⃣ 测试夹具(Fixtures)
setUp()
和 tearDown()
是在每个测试方法前后自动执行的:
class TestWithSetup(unittest.TestCase):
def setUp(self):
print("准备环境")
def tearDown(self):
print("清理环境")
def test_example(self):
self.assertEqual(1 + 1, 2)
运行结果:
准备环境
清理环境
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
还可以使用:
setUpClass(cls)
:整个类运行前运行(类方法)tearDownClass(cls)
:整个类运行后运行
7️⃣ 测试套件(Test Suite)
你可以将多个测试类组合成套件一起运行:
def suite():
suite = unittest.TestSuite()
suite.addTest(TestCalculator('test_add'))
suite.addTest(TestCalculator('test_divide'))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
8️⃣ Mock(模拟对象)
有时候你不希望真的调用外部依赖(比如数据库、API),就可以使用 unittest.mock
:
from unittest.mock import Mock
def get_price(api_client):
return api_client.get_price()
def test_get_price():
mock_api = Mock()
mock_api.get_price.return_value = 100
assert get_price(mock_api) == 100
9️⃣ 实战示例:测试一个类
# bank.py
class BankAccount:
def __init__(self, balance=0):
self.balance = balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
if amount > self.balance:
raise ValueError("Insufficient funds")
self.balance -= amount
# test_bank.py
import unittest
from bank import BankAccount
class TestBankAccount(unittest.TestCase):
def setUp(self):
self.acc = BankAccount(100)
def test_deposit(self):
self.acc.deposit(50)
self.assertEqual(self.acc.balance, 150)
def test_withdraw_valid(self):
self.acc.withdraw(30)
self.assertEqual(self.acc.balance, 70)
def test_withdraw_insufficient(self):
with self.assertRaises(ValueError):
self.acc.withdraw(200)
🔟 小结
内容 | 说明 |
---|---|
基本结构 | 创建类继承自 unittest.TestCase |
运行测试 | 直接运行 .py 文件或使用 unittest discover |
常用断言 | assertEqual , assertRaises 等 |
夹具方法 | setUp , tearDown |
模拟对象 | 使用 unittest.mock 模拟外部依赖 |
高级功能 | 测试套件、跳过测试、参数化 |
结语
第三百五十八篇博文写完,开心!!!!
今天,也是充满希望的一天。