1. 测试基础
1-1. 测试类型
测试类型 | 描述 | 适用场景 |
---|---|---|
单元测试 | 测试单个函数或类 | 函数逻辑、类方法 |
集成测试 | 测试多个组件交互 | 模块间交互、API 调用 |
功能测试 | 测试完整功能流程 | 用户操作流程 |
性能测试 | 测试系统性能 | 响应时间、并发处理 |
1-2. 测试框架
Python 主要测试框架:
框架 | 特点 | 适用场景 |
---|---|---|
unittest | Python 标准库 | 基础测试需求 |
pytest | 功能强大、灵活 | 复杂测试场景 |
nose2 | unittest 扩展 | 兼容 unittest |
doctest | 文档测试 | 简单函数测试 |
2. 单元测试
2-1. unittest 基础
python
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
# 每个测试方法前执行
self.test_string = "Hello, World!"
def tearDown(self):
# 每个测试方法后执行
self.test_string = None
def test_upper(self):
self.assertEqual(self.test_string.upper(), "HELLO, WORLD!")
def test_isupper(self):
self.assertTrue("HELLO".isupper())
self.assertFalse("Hello".isupper())
def test_split(self):
self.assertEqual(self.test_string.split(), ["Hello,", "World!"])
with self.assertRaises(TypeError):
self.test_string.split(2)
if __name__ == '__main__':
unittest.main()
2-2. pytest 基础
python
# test_sample.py
def test_addition():
assert 1 + 1 == 2
def test_subtraction():
assert 3 - 1 == 2
def test_multiplication():
assert 2 * 3 == 6
def test_division():
assert 6 / 2 == 3
with pytest.raises(ZeroDivisionError):
1 / 0
# 使用装饰器
@pytest.mark.parametrize("input,expected", [
(1, 1),
(2, 4),
(3, 9),
])
def test_square(input, expected):
assert input ** 2 == expected
3. 测试进阶
3-1. 测试夹具(Fixtures)
python
import pytest
@pytest.fixture
def database():
# 设置数据库连接
db = create_test_database()
yield db
# 清理数据库
db.close()
@pytest.fixture
def user(database):
# 使用其他夹具
return create_test_user(database)
def test_user_creation(user):
assert user.name == "Test User"
assert user.email == "test@example.com"
3-2. 测试覆盖率
python
# 使用 pytest-cov
# pytest --cov=myproject tests/
# 生成 HTML 报告
# pytest --cov=myproject --cov-report=html tests/
# 设置最低覆盖率要求
# pytest --cov=myproject --cov-fail-under=90 tests/
3-3. 模拟对象(Mock)
python
from unittest.mock import Mock, patch
def test_api_call():
# 创建模拟对象
mock_response = Mock()
mock_response.json.return_value = {"status": "success"}
# 使用 patch 装饰器
with patch('requests.get', return_value=mock_response):
result = make_api_call()
assert result["status"] == "success"
# 模拟类方法
class TestUser:
@patch('User.send_email')
def test_password_reset(self, mock_send_email):
user = User()
user.reset_password()
mock_send_email.assert_called_once()
4. 集成测试
4-1. API 测试
python
import requests
class TestAPI:
def setup_method(self):
self.base_url = "http://localhost:5000/api"
def test_get_users(self):
response = requests.get(f"{self.base_url}/users")
assert response.status_code == 200
assert isinstance(response.json(), list)
def test_create_user(self):
data = {"name": "Test User", "email": "test@example.com"}
response = requests.post(f"{self.base_url}/users", json=data)
assert response.status_code == 201
assert response.json()["name"] == "Test User"
4-2. 数据库测试
python
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
@pytest.fixture
def db_session():
# 创建测试数据库
engine = create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=engine)
session = Session()
# 创建表
Base.metadata.create_all(engine)
yield session
# 清理
session.close()
engine.dispose()
def test_user_creation(db_session):
user = User(name="Test User")
db_session.add(user)
db_session.commit()
result = db_session.query(User).first()
assert result.name == "Test User"
5. 测试最佳实践
5-1. 测试组织
project/
├── src/
│ └── myproject/
│ ├── __init__.py
│ ├── models.py
│ └── utils.py
└── tests/
├── __init__.py
├── conftest.py
├── test_models.py
└── test_utils.py
5-2. 测试命名
python
# 测试文件命名
test_models.py
test_utils.py
test_api.py
# 测试类命名
class TestUserModel:
class TestStringUtils:
class TestAPIClient:
# 测试方法命名
def test_user_creation():
def test_string_reverse():
def test_api_response():
5-3. 测试文档
python
def test_addition():
"""测试加法功能
测试场景:
1. 正数相加
2. 负数相加
3. 零值相加
"""
assert 1 + 1 == 2
assert -1 + -1 == -2
assert 0 + 0 == 0
6. 高级测试技术
6-1. 异步测试
python
import pytest
import asyncio
@pytest.mark.asyncio
async def test_async_function():
result = await async_function()
assert result == expected_result
@pytest.fixture
def event_loop():
loop = asyncio.get_event_loop()
yield loop
loop.close()
6-2. 性能测试
python
import pytest
import time
def test_performance():
start_time = time.time()
# 执行操作
result = perform_operation()
end_time = time.time()
execution_time = end_time - start_time
assert execution_time < 1.0 # 执行时间应小于1秒
6-3. 安全测试
python
def test_password_hashing():
password = "secret"
hashed = hash_password(password)
assert verify_password(password, hashed)
assert not verify_password("wrong", hashed)
def test_sql_injection():
with pytest.raises(SecurityError):
execute_query("'; DROP TABLE users; --")
7. 持续集成
7-1. GitHub Actions
yaml
# .github/workflows/test.yml
name: Python Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: |
pytest --cov=myproject tests/
7-2. 测试报告
python
# 生成测试报告
pytest --html=report.html
# 生成 JUnit XML 报告
pytest --junitxml=report.xml
# 生成覆盖率报告
pytest --cov=myproject --cov-report=xml
TIP
测试最佳实践:
- 编写可读性高的测试代码
- 使用有意义的测试命名
- 保持测试独立性和可重复性
- 适当使用模拟对象
- 定期运行测试套件
- 保持较高的测试覆盖率
- 在 CI/CD 流程中集成测试