本文目录导读:
- 单元测试(Unit Testing)
- 模拟与桩(Mocking & Stubbing)
- 参数化测试(Parameterized Testing)
- 异常与错误处理测试
- 集成测试(Integration Testing)
- 性能与负载测试(Performance Testing)
- 测试固件(Fixtures)的使用
- 常用测试场景速查表
Python测试的常用案例覆盖了从单元测试到集成测试、性能测试等多个层面,以下是按类别整理的常见测试场景和案例,附带简单的示例代码(主要使用 unittest 和 pytest)。
单元测试(Unit Testing)
这是最核心的测试类型,测试代码的最小可测试单元(通常是函数、方法、类)。
-
案例1:测试数学计算函数 验证加、减、乘、除等逻辑正确性,特别关注边界值(如除以0)。
# calculator.py def divide(a, b): if b == 0: raise ValueError("Cannot divide by zero") return a / b # test_calculator.py (使用unittest) import unittest from calculator import divide class TestCalculator(unittest.TestCase): def test_divide_normal(self): self.assertEqual(divide(10, 2), 5.0) def test_divide_by_zero(self): with self.assertRaises(ValueError): divide(10, 0) -
案例2:测试字符串处理函数 验证去除空格、大小写转换、拼接等操作。
# test_string_utils.py (使用pytest) def reverse_string(s): return s[::-1] def test_reverse_string(): assert reverse_string("hello") == "olleh" assert reverse_string("") == "" assert reverse_string("a") == "a" -
案例3:测试数据结构操作 测试列表、字典、集合的增删改查逻辑(如栈、队列模拟)。
def test_stack_push_pop(): stack = [] stack.append(1) stack.append(2) assert stack.pop() == 2 assert len(stack) == 1
模拟与桩(Mocking & Stubbing)
测试外部依赖(如API调用、数据库、文件系统)时,用mock替代真实资源。
-
案例1:模拟HTTP请求(避免真实网络) 测试一个从API获取用户信息的函数,而不实际发送请求。
# user_service.py import requests def get_user(user_id): response = requests.get(f"https://api.example.com/users/{user_id}") return response.json()['name'] # test_user_service.py from unittest.mock import patch from user_service import get_user @patch('user_service.requests.get') def test_get_user(mock_get): mock_get.return_value.json.return_value = {'name': 'Alice'} result = get_user(1) assert result == 'Alice' mock_get.assert_called_once_with("https://api.example.com/users/1") -
案例2:模拟文件读/写
# file_processor.py def read_config(filepath): with open(filepath, 'r') as f: return f.read() # test_file_processor.py from unittest.mock import mock_open, patch from file_processor import read_config def test_read_config(): m = mock_open(read_data='key=value') with patch('builtins.open', m): result = read_config('config.txt') assert result == 'key=value'
参数化测试(Parameterized Testing)
用同一套测试逻辑覆盖多组输入/输出数据,减少重复代码。
-
案例1:测试判断偶数函数
# test_even.py (使用pytest) import pytest def is_even(n): return n % 2 == 0 @pytest.mark.parametrize("input_val, expected", [ (2, True), (3, False), (0, True), (-2, True), (-3, False) ]) def test_is_even(input_val, expected): assert is_even(input_val) == expected -
案例2:测试数据验证器
@pytest.mark.parametrize("age, expected", [ (25, True), # 成年 (17, False), # 未成年 (18, True), # 边界 (0, False) # 非法(由业务逻辑决定) ]) def test_is_adult(age, expected): assert is_adult(age) == expected
异常与错误处理测试
确保代码在错误输入或异常状态下正确抛出或处理异常。
-
案例1:测试输入验证
def set_age(age): if not isinstance(age, int) or age < 0 or age > 150: raise ValueError("Age must be an integer between 0 and 150") return age def test_set_age_invalid(): with pytest.raises(ValueError, match="Age must be an integer"): set_age(-1) with pytest.raises(ValueError): set_age("old") # 字符串 -
案例2:测试数据库连接失败
from unittest.mock import patch def connect_to_db(): # 模拟连接失败 raise ConnectionError("DB is down") @patch('your_module.connect_to_db', side_effect=ConnectionError) def test_db_connection_fails(mock_connect): with pytest.raises(ConnectionError): # 业务逻辑中调用connect_to_db pass
集成测试(Integration Testing)
测试不同模块之间的交互是否正确(数据库、缓存、第三方服务)。
-
案例1:测试数据库CRUD操作(使用SQLite内存数据库)
import sqlite3 import pytest @pytest.fixture def db_connection(): conn = sqlite3.connect(':memory:') conn.execute("CREATE TABLE users (id INT, name TEXT)") conn.execute("INSERT INTO users VALUES (1, 'Alice')") return conn def test_get_user_name(db_connection): cursor = db_connection.execute("SELECT name FROM users WHERE id=1") name = cursor.fetchone()[0] assert name == "Alice" -
案例2:测试Flask应用端点
from flask import Flask import pytest app = Flask(__name__) @app.route('/hello/<name>') def hello(name): return f"Hello, {name}!" @pytest.fixture def client(): with app.test_client() as client: yield client def test_hello_endpoint(client): response = client.get('/hello/World') assert response.status_code == 200 assert b"Hello, World!" in response.data
性能与负载测试(Performance Testing)
使用 pytest-benchmark 或 timeit 测量函数执行时间。
-
案例1:比较不同算法的性能
# test_performance.py def test_sorting_performance(benchmark): data = [5, 3, 1, 4, 2] result = benchmark(sorted, data) # pytest-benchmark会自动计时 assert result == [1, 2, 3, 4, 5] -
案例2:测试API响应时间(简单使用time.time)
import time def test_api_response_speed(): start = time.time() # 调用你的API函数 time.sleep(0.1) # 模拟 elapsed = time.time() - start assert elapsed < 0.5, f"API太慢了: {elapsed}s"
测试固件(Fixtures)的使用
管理测试前后置条件,如创建临时文件、数据库连接、清理环境。
-
案例1:创建和销毁临时文件
import pytest import tempfile import os @pytest.fixture def temp_file(): # 设置:创建临时文件 file = tempfile.NamedTemporaryFile(delete=False) file.write(b"test data") file.close() yield file.name # 提供文件名给测试 # 清理:删除临时文件 os.unlink(file.name) def test_file_content(temp_file): with open(temp_file, 'r') as f: content = f.read() assert content == "test data"
常用测试场景速查表
| 类别 | 典型场景 | 推荐工具/方法 |
|---|---|---|
| 单元测试 | 函数逻辑、边界值、异常 | unittest.TestCase / pytest |
| 模拟外部依赖 | API调用、数据库、文件、时间 | unittest.mock.patch、pytest-mock |
| 参数化测试 | 多组输入/输出测试,如排列组合 | pytest.mark.parametrize |
| 异常测试 | 验证抛出正确的异常和错误信息 | pytest.raises / assertRaises |
| 集成测试 | 数据库CRUD、服务间交互、Flask/Django端点 | 测试客户端、内存数据库(如SQLite) |
| 性能测试 | 函数运行时间、并发模拟 | pytest-benchmark、timeit、locust |
| UI/端到端测试 | 模拟用户点击、表单提交 | Selenium、Playwright、Cypress |
| 快照测试 | 验证输出结果是否意外改变 | pytest-snapshot、syrupy |
在日常Python开发中,单元测试 + Mock + 参数化 是出现频率最高的组合,也是编写健壮代码的基础。
标签: 性能测试