文章目录
- **1. unittest是什么?**
- **2. unittest核心组件**
- **3. 如何使用unittest?**
- **3.1 编写测试用例**
- **3.2 运行测试**
- **3.3 参数化测试**
- **3.4 Mock对象(依赖隔离)**
- **3.5 跳过测试**
- **4. 常用插件与工具**
- **5. 面试常见问题**
- **5.1 理论问题**
- **5.2 实战编码**
- **6. 最佳实践**
- **6.1 测试设计原则**
- **6.2 高效技巧**
- **6.3 避免常见错误**
- **7. 示例项目结构**
1. unittest是什么?
unittest
是Python标准库中自带的单元测试框架,灵感来源于Java的JUnit。它提供了一套完整的测试结构,包括测试用例编写、断言、测试套件管理、测试运行和结果报告等功能,是Python开发者必备的测试工具。
2. unittest核心组件
组件/概念 | 作用 |
---|---|
TestCase | 测试用例的基类,每个测试方法需继承它并以test_ 开头。 |
TestSuite | 测试套件,用于组合多个测试用例或套件。 |
TestRunner | 运行测试并输出结果(如TextTestRunner )。 |
TestLoader | 自动发现和加载测试(如discover() 方法)。 |
断言方法 | 如assertEqual() 、assertTrue() 等,用于验证结果。 |
Fixture | setUp() 和tearDown() 方法,管理测试前后的资源。 |
3. 如何使用unittest?
3.1 编写测试用例
import unittestclass TestMath(unittest.TestCase):def test_add(self):self.assertEqual(1 + 1, 2) # 基础断言def test_divide(self):with self.assertRaises(ZeroDivisionError):1 / 0 # 验证异常
3.2 运行测试
-
命令行运行:
# 运行单个模块 python -m unittest test_module.py# 自动发现所有测试(匹配test*.py) python -m unittest discover
-
代码中运行:
if __name__ == "__main__":unittest.main()
3.3 参数化测试
原生不支持参数化,但可通过parameterized
库实现:
from parameterized import parameterizedclass TestMath(unittest.TestCase):@parameterized.expand([(2, 3, 5),(-1, 5, 4),])def test_add(self, a, b, expected):self.assertEqual(a + b, expected)
3.4 Mock对象(依赖隔离)
使用unittest.mock
模拟外部依赖:
from unittest.mock import patchclass TestAPI(unittest.TestCase):@patch("requests.get")def test_fetch_data(self, mock_get):mock_get.return_value.status_code = 200response = fetch_data() # 你的业务函数self.assertEqual(response.status_code, 200)
3.5 跳过测试
class TestExample(unittest.TestCase):@unittest.skip("功能未实现")def test_unfinished(self):pass@unittest.expectedFailuredef test_buggy_code(self):self.assertEqual(1, 2) # 预期失败
4. 常用插件与工具
工具/插件 | 用途 |
---|---|
HTMLTestRunner | 生成HTML格式的测试报告(需单独安装)。 |
coverage.py | 统计代码测试覆盖率,生成覆盖率报告。 |
parameterized | 支持参数化测试,简化多场景用例编写。 |
pytest | 第三方测试框架(非官方),兼容unittest且功能更强大。 |
5. 面试常见问题
5.1 理论问题
- unittest和pytest有什么区别?
unittest
是Python标准库,基于类;pytest
是第三方库,更简洁,支持参数化和Fixture依赖注入。
- 如何验证某个函数抛出了特定异常?
- 使用
self.assertRaises(ErrorType, func, args)
。
- 使用
setUp()
和tearDown()
的作用是什么?setUp()
在每个测试方法前执行,用于初始化;tearDown()
在每个测试方法后执行,用于清理资源。
- 如何模拟一个HTTP请求?
- 使用
unittest.mock.patch
装饰器模拟requests
库的行为。
- 使用
5.2 实战编码
- 编写一个测试类:验证字符串反转函数。
- 参数化测试:测试加法函数的多组输入。
- Mock场景:模拟数据库查询返回固定结果。
6. 最佳实践
6.1 测试设计原则
- 独立性:每个测试不依赖其他测试的结果。
- 原子性:一个测试只验证一个逻辑点。
- 可读性:测试方法名清晰(如
test_add_negative_numbers
)。
6.2 高效技巧
- 使用Fixture:通过
setUpClass()
初始化昂贵资源(如数据库连接)。 - 覆盖率检查:结合
coverage.py
确保覆盖核心逻辑。 - 持续集成(CI):将测试集成到GitHub Actions、Jenkins等工具中。
6.3 避免常见错误
- 忘记
test_
前缀:导致测试方法不被识别。 - 依赖全局状态:如修改全局变量影响其他测试。
- 过度Mock:Mock应仅用于外部依赖,而非业务核心逻辑。
7. 示例项目结构
my_project/
├── src/ # 业务代码
│ ├── math_utils.py # 数学工具函数
│ └── api_client.py # API客户端
└── tests/ # 测试代码├── test_math.py # 数学工具测试├── test_api.py # API客户端测试└── __init__.py # 标记为Python包
若有错误与不足请指出,关注DPT一起进步吧!!!