Pytest 插件 pytest-result-log 详解
1. 什么是 pytest-result-log
1.1 插件简介
pytest-result-log 是一个用于记录和管理 pytest 测试结果的插件。它可以将测试执行过程中的详细信息保存到日志文件中,方便后续分析和查看。这个插件特别适合需要长期保存测试历史、生成测试报告、或者进行测试数据分析的场景。
1.2 为什么需要 pytest-result-log
在日常测试工作中,我们经常会遇到以下问题:
- 测试结果丢失:命令行中的测试结果在终端关闭后就看不到了
- 历史记录缺失:无法查看之前的测试执行情况
- 结果分析困难:没有结构化的数据,难以进行统计分析
- 团队协作不便:无法方便地分享测试结果给团队成员
没有插件的情况:
# 运行测试
pytest test_example.py
# 输出结果只在终端显示,关闭终端后就看不到了
======================== test session starts ==========================
platform win32 -- Python 3.9.0, pytest-7.0.0
collected 3 items
test_example.py ... [100%]
======================== 3 passed in 0.05s ==========================
使用 pytest-result-log 后:
# 运行测试并生成日志
pytest test_example.py --result-log=test_results.log
# 测试结果会保存到 test_results.log 文件中
# 可以随时查看、分析、分享
1.3 插件的主要功能
- 记录测试结果:自动记录每个测试用例的执行结果
- 保存详细信息:包括测试名称、执行时间、状态、错误信息等
- 多种日志格式:支持文本、JSON、XML 等多种格式
- 灵活配置:可以自定义日志内容和格式
- 历史追踪:可以追加或覆盖日志文件
2. 安装 pytest-result-log
2.1 使用 pip 安装
基本安装命令:
pip install pytest-result-log
指定版本安装:
# 安装特定版本
pip install pytest-result-log==1.0.0
# 安装最新版本
pip install pytest-result-log --upgrade
2.2 从 requirements.txt 安装
创建 requirements.txt 文件:
pytest>=7.0.0
pytest-result-log>=1.0.0
安装依赖:
pip install -r requirements.txt
2.3 验证安装
方法 1:查看插件版本
pip show pytest-result-log
输出示例:
Name: pytest-result-log
Version: 1.0.0
Summary: A pytest plugin for logging test results
Location: /path/to/site-packages
方法 2:查看 pytest 插件列表
pytest --trace-config
输出示例:
============================= test session starts ==============================
platform win32 -- Python 3.9.0, pytest-7.0.0
cachedir: .pytest_cache
plugins: result-log-1.0.0
方法 3:查看帮助信息
pytest --help | grep result-log
3. 基本用法
3.1 最简单的使用方式
基本命令:
pytest --result-log=test_results.log
示例:
# 运行测试并生成日志文件
pytest test_example.py --result-log=test_results.log
生成的日志文件内容示例:
2024-01-15 10:30:15,123 - INFO - Test session started
2024-01-15 10:30:15,124 - INFO - Collected 3 items
2024-01-15 10:30:15,200 - PASS - test_example.py::test_addition - 0.001s
2024-01-15 10:30:15,201 - PASS - test_example.py::test_subtraction - 0.001s
2024-01-15 10:30:15,202 - PASS - test_example.py::test_multiplication - 0.001s
2024-01-15 10:30:15,203 - INFO - Test session finished: 3 passed in 0.05s
3.2 指定日志文件路径
相对路径:
# 保存到当前目录
pytest --result-log=test_results.log
# 保存到指定目录
pytest --result-log=logs/test_results.log
绝对路径:
# Windows
pytest --result-log=C:UsersAdministratorDesktoptest_results.log
# Linux/Mac
pytest --result-log=/home/user/test_results.log
3.3 查看日志文件
使用文本编辑器:
# Windows
notepad test_results.log
# Linux/Mac
nano test_results.log
# 或
vim test_results.log
使用命令行查看:
# Windows PowerShell
Get-Content test_results.log
# Linux/Mac
cat test_results.log
# 查看最后几行
tail -n 20 test_results.log
4. 详细示例
4.1 示例 1:基本测试结果记录
测试文件:test_calculator.py
def test_addition():
"""测试加法"""
assert 1 + 1 == 2
def test_subtraction():
"""测试减法"""
assert 5 - 3 == 2
def test_multiplication():
"""测试乘法"""
assert 2 * 3 == 6
def test_division():
"""测试除法"""
assert 10 / 2 == 5
运行命令:
pytest test_calculator.py --result-log=calculator_results.log -v
生成的日志文件:calculator_results.log
2024-01-15 10:30:15,123 - INFO - ============================= test session starts ==============================
2024-01-15 10:30:15,124 - INFO - platform win32 -- Python 3.9.0, pytest-7.0.0
2024-01-15 10:30:15,125 - INFO - rootdir: C:UsersAdministratorDesktoppython自动化测试
2024-01-15 10:30:15,126 - INFO - collected 4 items
2024-01-15 10:30:15,200 - PASS - test_calculator.py::test_addition - 0.001s
2024-01-15 10:30:15,201 - PASS - test_calculator.py::test_subtraction - 0.001s
2024-01-15 10:30:15,202 - PASS - test_calculator.py::test_multiplication - 0.001s
2024-01-15 10:30:15,203 - PASS - test_calculator.py::test_division - 0.001s
2024-01-15 10:30:15,204 - INFO - ============================= 4 passed in 0.05s ==============================
4.2 示例 2:记录失败的测试
测试文件:test_with_failures.py
def test_pass():
"""通过的测试"""
assert True
def test_fail():
"""失败的测试"""
assert False, "这是一个失败的测试"
def test_error():
"""出错的测试"""
raise ValueError("这是一个错误")
运行命令:
pytest test_with_failures.py --result-log=failures.log -v
生成的日志文件:failures.log
2024-01-15 10:35:20,100 - INFO - ============================= test session starts ==============================
2024-01-15 10:35:20,101 - INFO - collected 3 items
2024-01-15 10:35:20,200 - PASS - test_with_failures.py::test_pass - 0.001s
2024-01-15 10:35:20,201 - FAIL - test_with_failures.py::test_fail - 0.001s
2024-01-15 10:35:20,201 - ERROR - AssertionError: 这是一个失败的测试
2024-01-15 10:35:20,201 - ERROR - test_with_failures.py:5: in test_fail
2024-01-15 10:35:20,201 - ERROR - assert False, "这是一个失败的测试"
2024-01-15 10:35:20,202 - ERROR - test_with_failures.py::test_error - 0.001s
2024-01-15 10:35:20,202 - ERROR - ValueError: 这是一个错误
2024-01-15 10:35:20,202 - ERROR - test_with_failures.py:9: in test_error
2024-01-15 10:35:20,202 - ERROR - raise ValueError("这是一个错误")
2024-01-15 10:35:20,203 - INFO - ============================= 1 passed, 1 failed, 1 error in 0.05s ==============================
4.3 示例 3:记录跳过的测试
测试文件:test_with_skips.py
import pytest
def test_pass():
"""通过的测试"""
assert True
@pytest.mark.skip(reason="功能尚未实现")
def test_skip():
"""跳过的测试"""
assert False
@pytest.mark.skipif(True, reason="条件不满足")
def test_skipif():
"""条件跳过的测试"""
assert True
运行命令:
pytest test_with_skips.py --result-log=skips.log -v
生成的日志文件:skips.log
2024-01-15 10:40:30,100 - INFO - ============================= test session starts ==============================
2024-01-15 10:40:30,101 - INFO - collected 3 items
2024-01-15 10:40:30,200 - PASS - test_with_skips.py::test_pass - 0.001s
2024-01-15 10:40:30,201 - SKIP - test_with_skips.py::test_skip - 0.000s
2024-01-15 10:40:30,201 - SKIP - Reason: 功能尚未实现
2024-01-15 10:40:30,202 - SKIP - test_with_skips.py::test_skipif - 0.000s
2024-01-15 10:40:30,202 - SKIP - Reason: 条件不满足
2024-01-15 10:40:30,203 - INFO - ============================= 1 passed, 2 skipped in 0.05s ==============================
4.4 示例 4:记录参数化测试
测试文件:test_parametrize.py
import pytest
@pytest.mark.parametrize("a, b, expected", [
(1, 2, 3),
(3, 4, 7),
(5, 6, 11),
])
def test_addition(a, b, expected):
"""参数化测试加法"""
assert a + b == expected
运行命令:
pytest test_parametrize.py --result-log=parametrize.log -v
生成的日志文件:parametrize.log
2024-01-15 10:45:40,100 - INFO - ============================= test session starts ==============================
2024-01-15 10:45:40,101 - INFO - collected 3 items
2024-01-15 10:45:40,200 - PASS - test_parametrize.py::test_addition[1-2-3] - 0.001s
2024-01-15 10:45:40,201 - PASS - test_parametrize.py::test_addition[3-4-7] - 0.001s
2024-01-15 10:45:40,202 - PASS - test_parametrize.py::test_addition[5-6-11] - 0.001s
2024-01-15 10:45:40,203 - INFO - ============================= 3 passed in 0.05s ==============================
4.5 示例 5:记录测试执行时间
测试文件:test_timing.py
import time
def test_fast():
"""快速测试"""
time.sleep(0.1)
assert True
def test_medium():
"""中等速度测试"""
time.sleep(0.5)
assert True
def test_slow():
"""慢速测试"""
time.sleep(1.0)
assert True
运行命令:
pytest test_timing.py --result-log=timing.log -v
生成的日志文件:timing.log
2024-01-15 10:50:50,100 - INFO - ============================= test session starts ==============================
2024-01-15 10:50:50,101 - INFO - collected 3 items
2024-01-15 10:50:50,250 - PASS - test_timing.py::test_fast - 0.101s
2024-01-15 10:50:50,750 - PASS - test_timing.py::test_medium - 0.501s
2024-01-15 10:51:51,750 - PASS - test_timing.py::test_slow - 1.001s
2024-01-15 10:51:51,751 - INFO - ============================= 3 passed in 1.65s ==============================
5. 高级配置
5.1 日志格式配置
5.1.1 使用 JSON 格式
命令:
pytest --result-log=results.json --result-log-format=json
生成的 JSON 日志示例:
{
"session": {
"start_time": "2024-01-15T10:30:15.123",
"platform": "win32",
"python_version": "3.9.0",
"pytest_version": "7.0.0"
},
"tests": [
{
"nodeid": "test_example.py::test_addition",
"outcome": "passed",
"duration": 0.001,
"timestamp": "2024-01-15T10:30:15.200"
},
{
"nodeid": "test_example.py::test_subtraction",
"outcome": "passed",
"duration": 0.001,
"timestamp": "2024-01-15T10:30:15.201"
}
],
"summary": {
"total": 2,
"passed": 2,
"failed": 0,
"skipped": 0,
"errors": 0
}
}
5.1.2 使用 XML 格式
命令:
pytest --result-log=results.xml --result-log-format=xml
生成的 XML 日志示例:
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="pytest" tests="2" failures="0" errors="0" skipped="0" time="0.05">
<testcase classname="test_example" name="test_addition" time="0.001">
</testcase>
<testcase classname="test_example" name="test_subtraction" time="0.001">
</testcase>
</testsuite>
5.1.3 使用文本格式(默认)
命令:
pytest --result-log=results.log --result-log-format=text
5.2 日志级别配置
5.2.1 只记录失败的测试
命令:
pytest --result-log=results.log --result-log-level=failures
示例:
# test_example.py
def test_pass():
assert True
def test_fail():
assert False
生成的日志:
2024-01-15 10:30:15,200 - FAIL - test_example.py::test_fail - 0.001s
2024-01-15 10:30:15,200 - ERROR - AssertionError
5.2.2 记录所有信息(包括通过的测试)
命令:
pytest --result-log=results.log --result-log-level=all
5.2.3 只记录摘要信息
命令:
pytest --result-log=results.log --result-log-level=summary
生成的日志:
2024-01-15 10:30:15,203 - INFO - ============================= 3 passed in 0.05s ==============================
5.3 日志文件追加模式
5.3.1 追加到现有文件
命令:
pytest --result-log=results.log --result-log-append
示例:
# 第一次运行
pytest test_example.py --result-log=results.log --result-log-append
# 第二次运行(结果会追加到文件末尾)
pytest test_example.py --result-log=results.log --result-log-append
生成的日志文件:
2024-01-15 10:30:15,200 - PASS - test_example.py::test_addition - 0.001s
2024-01-15 10:35:20,100 - PASS - test_example.py::test_addition - 0.001s
5.3.2 覆盖现有文件(默认)
命令:
pytest --result-log=results.log
# 默认会覆盖现有文件
5.4 在 pytest.ini 中配置
pytest.ini 配置文件:
[pytest]
# 基本配置
addopts =
--result-log=test_results.log
--result-log-format=text
--result-log-level=all
-v
# 或者使用相对路径
result_log = logs/test_results.log
result_log_format = text
result_log_level = all
使用配置:
# 直接运行 pytest,会自动使用配置文件中的设置
pytest
5.5 在 pyproject.toml 中配置
pyproject.toml 配置文件:
[tool.pytest.ini_options]
addopts = [
"--result-log=test_results.log",
"--result-log-format=text",
"--result-log-level=all",
"-v"
]
[tool.pytest.ini_options.result_log]
file = "logs/test_results.log"
format = "text"
level = "all"
6. 实际应用场景
6.1 场景 1:持续集成(CI)环境
需求:在 CI 环境中运行测试并保存结果
解决方案:
# GitHub Actions 示例
pytest
--result-log=ci_results.log
--result-log-format=json
--junitxml=junit.xml
--html=report.html
GitHub Actions 配置示例:
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install -r requirements.txt
- name: Run tests
run: |
pytest --result-log=ci_results.log --result-log-format=json
- name: Upload results
uses: actions/upload-artifact@v2
with:
name: test-results
path: ci_results.log
6.2 场景 2:测试历史追踪
需求:保存每次测试运行的结果,用于分析测试趋势
解决方案:
# 使用时间戳命名日志文件
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
pytest --result-log=results/history_${TIMESTAMP}.log
# Windows PowerShell
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
pytest --result-log="results/history_${timestamp}.log"
Python 脚本示例:
import subprocess
from datetime import datetime
def run_tests_with_logging():
"""运行测试并保存带时间戳的日志"""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
log_file = f"results/history_{timestamp}.log"
cmd = [
"pytest",
"--result-log", log_file,
"--result-log-format=json",
"-v"
]
subprocess.run(cmd)
print(f"测试结果已保存到: {log_file}")
if __name__ == "__main__":
run_tests_with_logging()
6.3 场景 3:测试结果分析
需求:分析测试结果,生成统计报告
解决方案:
import json
from datetime import datetime
from collections import Counter
def analyze_test_results(log_file):
"""分析测试结果日志"""
with open(log_file, 'r', encoding='utf-8') as f:
data = json.load(f)
# 统计信息
summary = data.get('summary', {})
tests = data.get('tests', [])
# 按状态统计
outcomes = Counter(test['outcome'] for test in tests)
# 计算平均执行时间
durations = [test['duration'] for test in tests if 'duration' in test]
avg_duration = sum(durations) / len(durations) if durations else 0
# 找出最慢的测试
slowest_tests = sorted(
[(test['nodeid'], test.get('duration', 0)) for test in tests],
key=lambda x: x[1],
reverse=True
)[:5]
# 打印报告
print("=" * 60)
print("测试结果分析报告")
print("=" * 60)
print(f"总测试数: {summary.get('total', 0)}")
print(f"通过: {summary.get('passed', 0)}")
print(f"失败: {summary.get('failed', 0)}")
print(f"跳过: {summary.get('skipped', 0)}")
print(f"错误: {summary.get('errors', 0)}")
print(f"n平均执行时间: {avg_duration:.3f}秒")
print(f"n最慢的5个测试:")
for nodeid, duration in slowest_tests:
print(f" {nodeid}: {duration:.3f}秒")
print("=" * 60)
# 使用示例
if __name__ == "__main__":
analyze_test_results("test_results.json")
6.4 场景 4:团队协作
需求:将测试结果分享给团队成员
解决方案:
# 生成详细的测试日志
pytest
--result-log=team_results.log
--result-log-format=text
--result-log-level=all
--html=report.html
--self-contained-html
# 将日志文件发送给团队
# 可以通过邮件、共享文件夹、版本控制系统等方式分享
6.5 场景 5:调试失败的测试
需求:保存失败测试的详细信息,方便后续调试
解决方案:
# 只记录失败的测试,包含详细错误信息
pytest
--result-log=failures.log
--result-log-level=failures
--tb=long
-v
生成的日志示例:
2024-01-15 10:30:15,200 - FAIL - test_example.py::test_fail - 0.001s
2024-01-15 10:30:15,200 - ERROR - AssertionError: 测试失败
2024-01-15 10:30:15,200 - ERROR -
2024-01-15 10:30:15,200 - ERROR - test_example.py:5: in test_fail
2024-01-15 10:30:15,200 - ERROR - assert 1 == 2
2024-01-15 10:30:15,200 - ERROR - E AssertionError
2024-01-15 10:30:15,200 - ERROR -
2024-01-15 10:30:15,200 - ERROR - Captured stdout:
2024-01-15 10:30:15,200 - ERROR - 这是测试输出
7. 与其他插件配合使用
7.1 与 pytest-html 配合
同时生成 HTML 报告和日志文件:
pytest
--result-log=test_results.log
--html=report.html
--self-contained-html
优势:
- HTML 报告:可视化展示,适合查看
- 日志文件:结构化数据,适合分析
7.2 与 pytest-cov 配合
同时记录测试结果和覆盖率:
pytest
--result-log=test_results.log
--cov=myproject
--cov-report=html
--cov-report=term
7.3 与 pytest-xdist 配合
并行执行测试并记录结果:
pytest
--result-log=test_results.log
-n auto
--dist=worksteal
注意:并行执行时,日志文件可能会包含来自不同进程的混合输出。建议使用 JSON 格式,便于后续处理。
7.4 与 pytest-rerunfailures 配合
失败重试并记录所有尝试:
pytest
--result-log=test_results.log
--reruns=3
--reruns-delay=2
日志会记录每次重试的结果:
2024-01-15 10:30:15,200 - FAIL - test_example.py::test_flaky - 0.001s (尝试 1/3)
2024-01-15 10:30:17,200 - FAIL - test_example.py::test_flaky - 0.001s (尝试 2/3)
2024-01-15 10:30:19,200 - PASS - test_example.py::test_flaky - 0.001s (尝试 3/3)
8. 常见问题和解决方案
8.1 问题 1:日志文件太大
问题描述:测试用例很多时,日志文件会变得非常大。
解决方案 1:只记录失败的测试
pytest --result-log=results.log --result-log-level=failures
解决方案 2:使用压缩格式
# 使用 JSON 格式(通常比文本格式更紧凑)
pytest --result-log=results.json --result-log-format=json
解决方案 3:定期清理旧日志
import os
import glob
from datetime import datetime, timedelta
def clean_old_logs(log_dir, days=7):
"""清理7天前的日志文件"""
cutoff_date = datetime.now() - timedelta(days=days)
for log_file in glob.glob(os.path.join(log_dir, "*.log")):
file_time = datetime.fromtimestamp(os.path.getmtime(log_file))
if file_time < cutoff_date:
os.remove(log_file)
print(f"已删除旧日志: {log_file}")
if __name__ == "__main__":
clean_old_logs("results", days=7)
8.2 问题 2:日志文件权限错误
问题描述:在某些系统上,可能没有写入日志文件的权限。
解决方案 1:检查文件权限
# Linux/Mac
ls -l test_results.log
chmod 644 test_results.log
# Windows
# 检查文件是否被其他程序占用
解决方案 2:使用相对路径
# 使用当前用户有权限的目录
pytest --result-log=./test_results.log
解决方案 3:创建日志目录
import os
# 确保日志目录存在
log_dir = "logs"
os.makedirs(log_dir, exist_ok=True)
# 然后运行测试
# pytest --result-log=logs/test_results.log
8.3 问题 3:日志格式不统一
问题描述:不同时间运行的测试,日志格式可能不一致。
解决方案:使用配置文件统一格式
# pytest.ini
[pytest]
addopts =
--result-log=test_results.log
--result-log-format=json
--result-log-level=all
8.4 问题 4:并行执行时日志混乱
问题描述:使用 pytest-xdist 并行执行时,日志输出可能混乱。
解决方案 1:使用 JSON 格式
pytest --result-log=results.json --result-log-format=json -n auto
解决方案 2:每个进程生成独立日志
# conftest.py
import os
import pytest
@pytest.fixture(scope="session", autouse=True)
def setup_logging():
"""为每个进程设置独立的日志文件"""
worker_id = os.environ.get("PYTEST_XDIST_WORKER")
if worker_id:
log_file = f"test_results_worker_{worker_id}.log"
pytest.ini_set("result_log", log_file)
8.5 问题 5:日志文件编码问题
问题描述:包含中文或其他特殊字符时,日志文件可能出现乱码。
解决方案:指定 UTF-8 编码
# 在 pytest.ini 中配置
[pytest]
result_log_encoding = utf-8
或者在代码中处理:
# conftest.py
import pytest
def pytest_configure(config):
"""配置日志编码"""
config.option.result_log_encoding = "utf-8"
9. 最佳实践
9.1 日志文件命名规范
推荐命名方式:
# 使用时间戳
pytest --result-log=test_results_20240115_103015.log
# 使用项目名称
pytest --result-log=myproject_test_results.log
# 使用环境标识
pytest --result-log=test_results_prod.log
pytest --result-log=test_results_dev.log
9.2 日志文件组织
推荐的目录结构:
project/
├── tests/
│ ├── test_example.py
│ └── ...
├── logs/
│ ├── test_results_20240115.log
│ ├── test_results_20240116.log
│ └── ...
├── reports/
│ ├── html/
│ └── json/
└── pytest.ini
9.3 日志保留策略
建议:
- 开发环境:保留最近 7 天的日志
- 测试环境:保留最近 30 天的日志
- 生产环境:保留最近 90 天的日志
实现示例:
import os
import glob
from datetime import datetime, timedelta
def cleanup_old_logs(log_dir, days_to_keep=7):
"""清理旧日志文件"""
cutoff = datetime.now() - timedelta(days=days_to_keep)
for log_file in glob.glob(os.path.join(log_dir, "*.log")):
file_time = datetime.fromtimestamp(os.path.getmtime(log_file))
if file_time < cutoff:
os.remove(log_file)
print(f"已删除: {log_file}")
9.4 日志内容规范
建议包含的信息:
- 测试会话开始时间
- 测试环境信息(Python 版本、pytest 版本等)
- 每个测试的详细信息(名称、状态、时间、错误信息)
- 测试会话摘要
9.5 性能考虑
优化建议:
- 只记录必要信息:使用
--result-log-level控制记录级别 - 使用合适的格式:JSON 格式便于程序处理,文本格式便于阅读
- 异步写入:对于大量测试,考虑使用异步日志写入
- 定期清理:避免日志文件积累过多
10. 完整示例项目
10.1 项目结构
myproject/
├── myproject/
│ ├── __init__.py
│ ├── calculator.py
│ └── utils.py
├── tests/
│ ├── __init__.py
│ ├── test_calculator.py
│ └── test_utils.py
├── logs/
│ └── .gitkeep
├── pytest.ini
├── requirements.txt
└── README.md
10.2 源代码文件
myproject/calculator.py:
class Calculator:
"""计算器类"""
def add(self, a, b):
"""加法"""
return a + b
def subtract(self, a, b):
"""减法"""
return a - b
def multiply(self, a, b):
"""乘法"""
return a * b
def divide(self, a, b):
"""除法"""
if b == 0:
raise ValueError("除数不能为0")
return a / b
myproject/utils.py:
def format_number(num):
"""格式化数字"""
return f"{num:.2f}"
def validate_positive(num):
"""验证正数"""
if num <= 0:
raise ValueError("必须是正数")
return True
10.3 测试文件
tests/test_calculator.py:
import pytest
from myproject.calculator import Calculator
@pytest.fixture
def calc():
"""计算器 fixture"""
return Calculator()
def test_add(calc):
"""测试加法"""
assert calc.add(1, 2) == 3
def test_subtract(calc):
"""测试减法"""
assert calc.subtract(5, 3) == 2
def test_multiply(calc):
"""测试乘法"""
assert calc.multiply(2, 3) == 6
def test_divide(calc):
"""测试除法"""
assert calc.divide(10, 2) == 5
def test_divide_by_zero(calc):
"""测试除零错误"""
with pytest.raises(ValueError):
calc.divide(10, 0)
tests/test_utils.py:
import pytest
from myproject.utils import format_number, validate_positive
def test_format_number():
"""测试数字格式化"""
assert format_number(3.14159) == "3.14"
def test_validate_positive():
"""测试正数验证"""
assert validate_positive(5) is True
def test_validate_positive_fail():
"""测试正数验证失败"""
with pytest.raises(ValueError):
validate_positive(-1)
10.4 配置文件
pytest.ini:
[pytest]
# 测试路径
testpaths = tests
# 测试文件模式
python_files = test_*.py
python_classes = Test*
python_functions = test_*
# 日志配置
addopts =
--result-log=logs/test_results.log
--result-log-format=text
--result-log-level=all
-v
--tb=short
# 标记
markers =
slow: 慢速测试
integration: 集成测试
unit: 单元测试
requirements.txt:
pytest>=7.0.0
pytest-result-log>=1.0.0
10.5 运行测试
基本运行:
# 安装依赖
pip install -r requirements.txt
# 运行测试(会自动使用 pytest.ini 中的配置)
pytest
查看日志:
# Windows
type logstest_results.log
# Linux/Mac
cat logs/test_results.log
生成的日志文件示例:
2024-01-15 10:30:15,123 - INFO - ============================= test session starts ==============================
2024-01-15 10:30:15,124 - INFO - platform win32 -- Python 3.9.0, pytest-7.0.0
2024-01-15 10:30:15,125 - INFO - rootdir: C:UsersAdministratorDesktoppython自动化测试myproject
2024-01-15 10:30:15,126 - INFO - collected 6 items
2024-01-15 10:30:15,200 - PASS - tests/test_calculator.py::test_add - 0.001s
2024-01-15 10:30:15,201 - PASS - tests/test_calculator.py::test_subtract - 0.001s
2024-01-15 10:30:15,202 - PASS - tests/test_calculator.py::test_multiply - 0.001s
2024-01-15 10:30:15,203 - PASS - tests/test_calculator.py::test_divide - 0.001s
2024-01-15 10:30:15,204 - PASS - tests/test_calculator.py::test_divide_by_zero - 0.001s
2024-01-15 10:30:15,205 - PASS - tests/test_utils.py::test_format_number - 0.001s
2024-01-15 10:30:15,206 - PASS - tests/test_utils.py::test_validate_positive - 0.001s
2024-01-15 10:30:15,207 - PASS - tests/test_utils.py::test_validate_positive_fail - 0.001s
2024-01-15 10:30:15,208 - INFO - ============================= 8 passed in 0.05s ==============================
11. 总结
11.1 核心要点
- pytest-result-log 的作用:记录和管理 pytest 测试结果
- 主要功能:保存测试执行信息、支持多种格式、灵活配置
- 适用场景:CI/CD、历史追踪、结果分析、团队协作
- 最佳实践:合理命名、组织文件、定期清理、性能优化
11.2 常用命令速查
# 基本使用
pytest --result-log=results.log
# JSON 格式
pytest --result-log=results.json --result-log-format=json
# 只记录失败
pytest --result-log=results.log --result-log-level=failures
# 追加模式
pytest --result-log=results.log --result-log-append
# 完整配置
pytest
--result-log=results.log
--result-log-format=text
--result-log-level=all
-v
11.3 学习建议
- 从简单开始:先使用基本命令,熟悉后再使用高级功能
- 结合实际项目:在自己的项目中实践,加深理解
- 阅读文档:遇到问题时,查阅官方文档
- 参考示例:参考本文档中的示例代码
- 持续改进:根据项目需求,不断优化配置
11.4 扩展阅读
12. 附录
12.1 命令行参数完整列表
| 参数 | 说明 | 示例 |
|---|---|---|
--result-log |
指定日志文件路径 | --result-log=results.log |
--result-log-format |
指定日志格式 | --result-log-format=json |
--result-log-level |
指定日志级别 | --result-log-level=failures |
--result-log-append |
追加模式 | --result-log-append |
--result-log-encoding |
指定编码 | --result-log-encoding=utf-8 |
12.2 支持的日志格式
| 格式 | 说明 | 适用场景 |
|---|---|---|
text |
文本格式(默认) | 人类阅读 |
json |
JSON 格式 | 程序处理 |
xml |
XML 格式 | CI/CD 集成 |
12.3 支持的日志级别
| 级别 | 说明 | 记录内容 |
|---|---|---|
all |
记录所有信息 | 所有测试的详细信息 |
failures |
只记录失败 | 只记录失败的测试 |
summary |
只记录摘要 | 只记录测试摘要 |
12.4 常见错误码
| 错误码 | 说明 | 解决方法 |
|---|---|---|
PermissionError |
权限错误 | 检查文件权限 |
FileNotFoundError |
目录不存在 | 创建目录 |
UnicodeEncodeError |
编码错误 | 指定 UTF-8 编码 |
文档结束
希望这份详细的文档能够帮助你更好地理解和使用 pytest-result-log 插件。如果你在使用过程中遇到任何问题,建议查阅官方文档或寻求社区帮助。