
为每一个Python项目创建独立的虚拟环境是一个被广泛推荐的最佳实践和良好习惯,它有很多好处。还推荐使用 Pycharm ,它挺牛的。
确定项目结构
项目都会有项目结构,那最优的项目结构是啥?答案是没有答案。因为它高度依赖于项目的具体类型和使用的编程语言等因素。不过你可以参考本文中的项目结构。
因为需要集成 pytest 和 allure,项目结构可以如下:
Project/
│
├── allure/ # allure 目录,集成 allure 相关文件
│
├── common/ # 通用的功能实现可以放在这里
│ ├── __init__.py # 包初始化文件,可以定义一些变量或执行一些操作。当然里面什么都不写也可以。
│ └── tool.py # 具体功能实现,比如 database.py
│
├── configs/ # 配置文件目录,一些配置类型的文件都可以放在这里
│
├── fixtures/ # 夹具函数目录
│ ├── __init__.py # 包初始化文件,可以定义一些变量或执行一些操作。当然里面什么都不写也可以。
│ ├── login_fixture.py # 登录模块 所需夹具函数
│ └── user_fixture.py # 用户模块 所需夹具函数
│
├── tests/ # 测试用例目录
│ ├── conftest.py # 包含适用于所有测试的通用配置和 fixture
│ ├── __init__.py # 包初始化文件
│ └── login/ # login 模块测试目录
│ ├── conftest.py # 适用于 login 模块的通用配置和 fixture
│ └── test_login.py # 测试 login 模块的测试用例
├── app.py # 项目启动文件
├── requirements.txt # 项目依赖项列表
├── pytest.ini # pytest 相关配置,比如自定义 mark 标记
└── README.md # 项目说明文档
安装依赖项
安装 pytest :
pip install -U pytest
安装 allure-pytest :
pip install allure-pytest
Python中,requests 是比较好用的请求库,按需安装 :
pip install requests
编辑启动文件
编辑 app.py ,作为项目的启动文件:
import pytest
import sys
import logging
import argparse
from pathlib import Path
import subprocess
# 自定义日志格式
LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s'
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)
logger = logging.getLogger(__name__)
# 定义pytest配置文件路径
PYTEST_CONFIG_PATH = "pytest.ini"
# 项目根目录路径
parent_dir = Path(__file__).resolve().parent
# 构建 Allure 命令的绝对路径
allure_bin_path = parent_dir / "allure" / "bin" / "allure.bat"
# 运行测试
def run_tests(test_target: str, testprint: str, tb: str, mark: str) -> int:
"""
运行测试并生成Allure结果数据
:param test_target: 测试目标路径(支持文件、目录、节点ID如 test_xxx.py::test_func)
:param testprint: 控制输出信息
:param tb: traceback 格式
:param mark: 测试标记
:return: 退出码
"""
# 提取实际文件或目录路径(去除 :: 之后的节点名)
path_part = test_target.split("::")[0]
if not Path(path_part).exists():
logger.error(f"测试目标文件或目录不存在: {path_part}")
return 1
# 构建pytest参数
pytest_args = ["--clean-alluredir", "--alluredir=./result"]
if (parent_dir / PYTEST_CONFIG_PATH).exists():
pytest_args.extend(["-c", str(parent_dir / PYTEST_CONFIG_PATH)])
else:
logger.warning("未找到配置文件,将使用默认配置")
# 添加输出控制参数
if testprint:
pytest_args.append("-" + testprint)
pytest_args.extend([test_target, "--tb=" + tb])
if mark:
pytest_args.extend(["-m", mark])
try:
logger.info(f"开始运行测试,目标: {test_target}")
exit_code = pytest.main(pytest_args)
exit_messages = {
0: "✅ 全部测试用例通过",
1: "⚠️ 部分测试用例未通过",
2: "❌ 测试过程中有中断或其他非正常终止",
3: "❌ 内部错误",
4: "❌ pytest无法找到任何测试用例",
5: "❌ 命令行解析错误"
}
logger.info(exit_messages.get(exit_code, f"❓ 未知的退出码: {exit_code}"))
return exit_code
except Exception as e:
logger.exception("运行测试时发生致命错误:")
logger.debug("异常详情:", exc_info=True)
return 1
# 构建参数解析器
def parse_arguments() -> argparse.Namespace:
"""
解析命令行参数:
test_target:测试目标路径
testprint:控制输出信息,默认为空;-p + 参数
可输入参数有"", "v", "ra", "rA", "rp", "rx", "rs", "rN", "vra", "vrA", "vrp", "vrx", "vrs", "vrN"
具体作用参考 pytest 官方文档
tb:控制输出信息,默认为 auto;-tb + 参数
可输入参数有"auto", "long", "short", "line", "native", "no"
具体作用参考 pytest 官方文档
mark:测试标记,默认为空;-m + 参数;参数为 pytest.ini 中自定义的 mark 标记
:return: 解析后的参数
"""
parser = argparse.ArgumentParser(description="使用指定的命令运行 pytest 测试")
# 指定测试目录、文件、测试组或测试用例,默认为 tests/
parser.add_argument(
'test_target',
nargs='?',
type=str,
default="tests/",
help='指定测试目录文件 (默认: tests/)'
)
# 添加 pytest 参数 testprint、 tb
parser.add_argument(
'-p', '--testprint',
nargs='?',
type=str,
default="",
choices=["", "v", "ra", "rA", "rp", "rx", "rs", "rN", "vra", "vrA", "vrp", "vrx", "vrs", "vrN"],
help='控制测试输出信息(例如:v=详细输出,ra=记录所有测试结果,详细选项参考 pytest 文档)'
)
parser.add_argument(
'-tb', '--tb',
nargs='?',
type=str,
default="auto",
choices=["auto", "long", "short", "line", "native", "no"],
help='控制 traceback 输出格式(例如:auto=自动选择,long=详细,short=简短)'
)
parser.add_argument(
'-m', '--mark',
nargs='?',
type=str,
help='指定测试标记(例如:smoke=运行标记为smoke的测试用例)'
)
return parser.parse_args()
# 生成测试结果报告
def allure_report():
"""
使用 Allure 生成测试报告
"""
if not allure_bin_path.exists():
logger.error(f"Allure 可执行文件不存在: {allure_bin_path}")
return
result_dir = parent_dir / "result"
if not result_dir.exists():
logger.error("测试结果目录不存在,无法生成报告")
return
try:
logger.info("开始生成 Allure 测试报告")
allure_command = [
str(allure_bin_path),
"generate",
str(result_dir),
"-o", "report",
"--clean"
]
result = subprocess.run(
allure_command,
check=True,
text=True,
capture_output=True,
cwd=str(parent_dir)
)
logger.info("Allure 报告成功生成至 report 目录")
logger.debug(result.stdout)
except subprocess.CalledProcessError as e:
logger.error(f"生成 Allure 报告时出错: {e}")
logger.error(e.stderr)
logger.debug(e.stdout)
# 主函数
def main():
args = parse_arguments()
exit_code = run_tests(args.test_target, args.testprint, args.tb, args.mark)
allure_report()
sys.exit(exit_code)
if __name__ == "__main__":
main()
使用说明:
python .\app.py 测试目标路径 -p 参数 -tb 参数 -m 自定义mark标记
其中:
-
测试目标路径:默认为 tests/,这个参数可以指定要运行的范围,目录下、测试组下、测试用例。
比如: python .\app.py tests\test_mod.py::test_list_fail
-
-p:默认为空,这个参数可以控制打印台输出信息的详细程度。
比如:python .\app.py -p v
-
-tb:默认为 auto,这个参数可以控制打印台输出信息的详细程度。
比如:python .\app.py -tb short
-
-m:默认为空,这个参数可以运行特定标记的测试用例。
比如:python .\app.py -m smoke
THEEND

© 转载需要保留原始链接,未经明确许可,禁止商业使用。CC BY-NC-ND 4.0