Skip to content

1. 测试基础

1-1. 测试类型

测试类型描述适用场景
单元测试测试单个函数或类函数逻辑、类方法
集成测试测试多个组件交互模块间交互、API 调用
功能测试测试完整功能流程用户操作流程
性能测试测试系统性能响应时间、并发处理

1-2. 测试框架

Python 主要测试框架:

框架特点适用场景
unittestPython 标准库基础测试需求
pytest功能强大、灵活复杂测试场景
nose2unittest 扩展兼容 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

测试最佳实践:

  1. 编写可读性高的测试代码
  2. 使用有意义的测试命名
  3. 保持测试独立性和可重复性
  4. 适当使用模拟对象
  5. 定期运行测试套件
  6. 保持较高的测试覆盖率
  7. 在 CI/CD 流程中集成测试