Python: PyTest介绍和使用
·
文章目录
PyTest 介绍和使用指南
什么是 PyTest?
PyTest 是一个功能强大的 Python 测试框架,具有以下特点:
- 简单易用:只需要使用
assert语句即可编写测试 - 功能丰富:支持参数化测试、fixture、插件系统等高级功能
- 自动发现:自动发现并运行测试文件
- 详细报告:提供清晰的测试结果和失败信息
安装 PyTest
pip install pytest
基本用法
1. 简单的测试示例
创建一个测试文件 test_sample.py:
# test_sample.py
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0
assert add(0, 0) == 0
运行测试:
pytest test_sample.py
2. 测试类和分组
# test_calculator.py
class Calculator:
def multiply(self, a, b):
return a * b
def divide(self, a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
class TestCalculator:
def test_multiply(self):
calc = Calculator()
assert calc.multiply(3, 4) == 12
assert calc.multiply(-2, 5) == -10
def test_divide(self):
calc = Calculator()
assert calc.divide(10, 2) == 5
assert calc.divide(5, 2) == 2.5
def test_divide_by_zero(self):
calc = Calculator()
with pytest.raises(ValueError, match="Cannot divide by zero"):
calc.divide(10, 0)
高级功能
1. Fixture(夹具)
Fixture 用于为测试提供预设环境和数据:
import pytest
@pytest.fixture
def sample_data():
"""提供测试数据"""
return {"name": "Alice", "age": 30, "scores": [85, 92, 78]}
@pytest.fixture
def database_connection():
"""模拟数据库连接"""
connection = "mock_database_connection"
yield connection # 测试执行前设置,yield 后清理
# 清理代码
connection = None
def test_data_processing(sample_data, database_connection):
assert sample_data["name"] == "Alice"
assert len(sample_data["scores"]) == 3
assert database_connection is not None
2. 参数化测试
import pytest
@pytest.mark.parametrize("input_a, input_b, expected", [
(2, 3, 5),
(0, 0, 0),
(-1, 1, 0),
(100, 200, 300)
])
def test_addition(input_a, input_b, expected):
assert input_a + input_b == expected
@pytest.mark.parametrize("username, password, expected_result", [
("admin", "secret", True),
("user", "wrong", False),
("", "", False)
])
def test_login(username, password, expected_result):
# 模拟登录逻辑
result = login_function(username, password)
assert result == expected_result
3. 标记(Markers)
import pytest
@pytest.mark.slow
def test_expensive_operation():
# 这个测试运行很慢
result = expensive_computation()
assert result is not None
@pytest.mark.skip(reason="功能尚未实现")
def test_unimplemented_feature():
assert False
@pytest.mark.skipif(sys.version_info < (3, 7), reason="需要 Python 3.7 或更高版本")
def test_python37_feature():
# 使用 Python 3.7 特性的测试
pass
@pytest.mark.xfail
def test_experimental_feature():
# 预期会失败的测试
assert experimental_function() == "expected"
常用命令行选项
# 运行所有测试
pytest
# 运行特定文件
pytest test_module.py
# 运行特定目录
pytest tests/
# 运行包含特定字符串的测试
pytest -k "add" # 运行所有包含 "add" 的测试
# 运行标记的测试
pytest -m slow # 只运行标记为 @pytest.mark.slow 的测试
# 显示详细输出
pytest -v
# 在第一次失败时停止
pytest -x
# 生成测试报告
pytest --html=report.html
# 并行运行测试
pytest -n 4 # 使用 4 个进程
测试目录结构
project/
├── src/
│ └── mymodule.py
├── tests/
│ ├── __init__.py
│ ├── conftest.py # 共享的 fixture
│ ├── test_basic.py
│ ├── test_advanced.py
│ └── fixtures/
│ └── test_data.py
├── setup.py
└── pytest.ini # pytest 配置文件
配置文件 pytest.ini
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts = -v --tb=short
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
integration: integration tests
断言和异常测试
import pytest
def test_assertions():
# 基本断言
assert 1 + 1 == 2
# 包含性检查
assert "hello" in "hello world"
assert 1 in [1, 2, 3]
# 类型检查
assert isinstance("hello", str)
# 近似相等
assert 0.1 + 0.2 == pytest.approx(0.3)
def test_exceptions():
# 测试异常
with pytest.raises(ValueError):
int("not_a_number")
# 测试异常消息
with pytest.raises(ValueError, match="invalid literal"):
int("not_a_number")
实用技巧
1. 临时目录
def test_temp_files(tmp_path):
# tmp_path 是 pytest 提供的临时目录 fixture
test_file = tmp_path / "test.txt"
test_file.write_text("Hello, pytest!")
assert test_file.read_text() == "Hello, pytest!"
assert test_file.exists()
2. Monkeypatch
def test_monkeypatch(monkeypatch):
# 临时修改函数或属性
import os
def mock_getcwd():
return "/mock/directory"
monkeypatch.setattr(os, "getcwd", mock_getcwd)
assert os.getcwd() == "/mock/directory"
3. 捕获输出
def test_output(capsys):
print("Hello, World!")
captured = capsys.readouterr()
assert captured.out == "Hello, World!\n"
总结
PyTest 是一个强大而灵活的测试框架,通过简单的语法和丰富的功能,让编写和维护测试变得更加容易。掌握 PyTest 可以显著提高代码质量和开发效率。
更多推荐


所有评论(0)