接口自动化测试学习
一、自动化测试项目的目录结构
在自动化测试项目中,良好的目录结构设计对于项目的可维护性、可扩展性和团队协作非常重要。

| 目录名称 | 含义 | 用途 |
|---|---|---|
| .venv | 虚拟环境目录 | 用于隔离项目依赖,确保不同项目之间不会因为依赖包版本冲突而出现问题 |
| base | 基础模块或基类目录 | 通常存放一些基础的类或者函数,这些类或函数会被其他模块广泛使用 |
| common | 公共工具或辅助功能目录 | 存放一些通用的工具类或函数,比如日志处理、文件读写、数据处理等。这些工具在整个项目中被频繁调用,但不直接参与具体的业务逻辑。 |
| conf | 配置文件目录 | 存放项目的配置文件,如数据库连接信息、API接口地址、环境变量等。这些配置文件通常以 .yaml, .json, .ini 等格式存储,便于管理和修改。 |
| data | 测试数据目录 | 存放测试过程中需要使用的数据文件,如 Excel 表格、CSV 文件、JSON 文件等。这些数据可能包括测试用例的数据、预期结果等。 |
| log | 日志文件目录 | 存放程序运行时生成的日志文件。日志记录了程序运行过程中的各种信息,包括调试信息、错误信息等。 |
| testcase | 测试用例目录 | 存放所有的测试用例文件。每个测试用例文件通常对应一个特定的功能或模块的测试。 |
二、conf 可复用的配置文件封装
- 包含:
- 全局路径与日志设置(setting.py)
- 接口环境与数据库配置文件(config.yaml)
- 配置读取工具类(operationConfig.py)
- 这套配置系统的优势
| 统一管理路径 | setting.py + FILE_PATH | 不用手动拼接路径,项目可移植 |
| 集中管理配置 | config.yaml | 修改环境只需改一个文件 |
| 简化配置读取 | OperationConfig 类 | 封装后调用简单,代码更优雅 |
| 支持多环境切换 | host / online | 可用于测试、预发、生产环境 |
步骤一:全局配置文件 conf/setting.py
文件路径:conf/setting.py
import os
import sys
import logging
"""获取项目根目录(即 conf 的上一级)"""
DIR_path = os.path.dirname(os.path.dirname(__file__))
"""将根目录添加到 Python 的模块搜索路径中,确保无论从哪个目录启动脚本,Python 都能找到项目的根模块"""
sys.path.append(DIR_path)
"""日志输出级别设置"""
LOG_LEVEL = logging.DEBUG """写入日志文件时的级别"""
STREAM_LOG_LEVEL = logging.WARNING """输出到控制台的级别"""
"""项目中常用文件的路径统一管理(集中配置)"""
FILE_PATH = {
'extract': os.path.join(DIR_path, 'extract.yaml'), """数据提取token文件"""
'login': os.path.join(DIR_path, 'testcase', 'login.yaml'), """登录测试数据文件"""
'conf': os.path.join(DIR_path, 'conf', 'config.yaml') """配置文件路径"""
}
- 解析说明:
| 代码 | 含义 |
|---|---|
| os.path.dirname(file) | 获取当前文件所在的目录(这里是 conf) |
| os.path.dirname(…) 嵌套一次 | 获取上一级目录(项目根目录) |
| sys.path.append(…) | 涉及跨文件夹引用时,让 Python 能够找到项目根目录下的所有模块(如 testcase) |
| LOG_LEVEL = logging.DEBUG | (DEBUG调试信息,最详细)把 DEBUG 以上级别的运行日志信息都写进文件 |
| STREAM_LOG_LEVEL = logging.WARNING | 控制台只显示 warning(可能有问题,但程序还能运行)以上级别的错误信息 |
| FILE_PATH 字典 | 把所有重要文件路径集中管理,避免硬编码路径 |
- 使用方法(在其他文件中引用)
好处:以后如果移动项目,只需改一处路径,不用到处改 …/testcase/…
from conf.setting import FILE_PATH
"""使用示例"""
login_yaml_path = FILE_PATH['login']
print(login_yaml_path) """输出:D:\my_automation\testcase\login.yaml"""
步骤二:环境配置文件 conf/config.yaml ( 不使用 .ini )
YAML 是比 .ini 更强大、更灵活的配置格式,尤其适合自动化测试项目
文件路径:conf/config.yaml
---- 接口环境配置
api_envi:
host: http://127.0.0.1:8787
online: http://www.baidu.com
---- 数据库配置
mysql:
host: 127.0.0.1
port: 3306
username: root
password: 123456
database: sys
---- 可以轻松添加更多配置
redis:
host: 127.0.0.1
port: 6379
---- 支持复杂结构(INI 做不到!)
test_data:
login:
- username: admin
password: 123456
- username: test
password: 654321
- 常见用途:
- api_envi:存放不同环境的接口地址(本地、测试、线上)
- MYSQL:数据库连接信息(可用于数据库断言)
步骤三:配置YAML 读取工具类 operationConfig.py
文件路径:operationConfig.py(放在根目录)
import yaml
from conf.setting import FILE_PATH
class OperationYaml:
"""封装读取 YAML 配置文件"""
def __init__(self, file_path=None):
if file_path is None:
self.__file_path = FILE_PATH['conf']
else:
self.__file_path = file_path
self.__data = None """缓存数据,避免重复读文件"""
self.__load_data()
def __load_data(self):
"""私有方法:加载 YAML 文件"""
try:
with open(self.__file_path, 'r', encoding='utf-8') as f:
self.__data = yaml.safe_load(f) """安全解析 YAML"""
except Exception as e:
print(f"读取 YAML 文件失败:{e}")
self.__data = {}
def get(self, *keys):
"""
通用获取方法,支持多层嵌套
:param keys: 键的路径,如 get('api_envi', 'host')
:return: 对应值
"""
if not self.__data:
return None
data = self.__data
for key in keys:
if isinstance(data, dict) and key in data:
data = data[key]
else:
print(f"找不到路径: {keys}")
return None
return data
def get_envi(self, option):
"""快捷方法:获取接口环境地址"""
return self.get('api_envi', option)
def get_mysql(self, key):
"""快捷方法:获取数据库配置"""
return self.get('mysql', key)
"""测试代码"""
if __name__ == '__main__':
yml = OperationYaml()
print("本地接口:", yml.get_envi('host'))
print("数据库用户:", yml.get_mysql('username'))
print("所有登录数据:", yml.get('test_data', 'login'))
- 核心功能解析:
| 功能 | 解析 |
|---|---|
| self.__file_path = FILE_PATH[‘conf’] (双下划线) | 将配置文件路径设置为“私有”属性,禁止外部读取并修改 |
| self.__data = None | 提前声明一个“缓存变量”,避免重复读文件 |
| self.__load_data() | 构造对象时自动加载__load_data方法,即刻可用 |
| get(*keys) | 支持多层嵌套的通用取值方法 |
| get_envi(option) 和 get_mysql(key) | 核心功能:快捷方法 |
get(*keys) 支持多层嵌套的通用取值方法举例(yaml)
- 若yaml里有嵌套格式
test_data:
login:
- username: admin
password: 123456
- 取第一个用户的用户名
yml.get('test_data', 'login', 0, 'username')
→ 返回 ‘admin’
- get(*keys)优势
| 特性 | 说明 |
|---|---|
| *keys | 可变参数,支持任意层级(2层、3层、4层都行) |
| 逐层查找 | data = data[key],像爬楼梯一样深入结构 |
| 类型检查 | isinstance(data, dict) 防止在 list 上用字符串当 key |
| 安全返回 | 找不到就返回 None,不抛异常 |
步骤四:实际使用示例(写个测试脚本)
文件路径:test_example.py
from operationConfig import OperationYaml
"""创建配置操作对象"""
config = OperationYaml()
"""获取接口地址"""
base_url = config.get_envi('host')
print("当前接口环境:", base_url)
"""获取数据库信息(可用于数据库验证)"""
db_host = config.get_mysql('host')
db_user = config.get_mysql('username')
print(f"数据库连接: {db_user}@{db_host}")
- 运行结果
当前接口环境: http://127.0.0.1:8787
数据库连接: root@127.0.0.1
-------------------------------------------------------------------------------
Pytest 框架基础知识
一、Pytest优势
- 1)pytest是一个很成熟的单元测试框架(比 unittest 更好用)
- 2)pytest可与requests、selenium结合实现web自动化、接口自动化和App自动化
- 3)pytest可以实现测试用例的跳过 以及测试用例的失败重跑机制
- 4)pytest可以与allure结合生成美观的测试报告
- 5)pytest与Jenkins持续集成
- 6)pytest有非常丰富的插件功能(重要!!)
所有插件都需要安装,安装方法:
pip install pytest-rerunfailures -i https://pypi.tuna.tsinghua.edu.cn/simple/
| 插件名 | 作用 |
|---|---|
| pytest-html | 生成html格式的测试报告 |
| pytest-xdist | 测试用例分布式执行 |
| pytest-ordering | 用来改变我们测试用例的执行顺序 |
| pytest-rerunfailures | 测试用例失败后重跑 |
| allure-pytest | 用于生成美观的allure测试报告 |
二、基础知识
1. pytest安装
- 安装
pip install -U pytest
- 验证安装(会展示当前已安装版本)
pytest --version
2. 测试用例的使用规则以及基础使用
- 1.模块名称必须以 test_ 开头或者以 _test 结尾
- 2.测试类必须以 Test 开头,并且不能有 _ init _ 方法
- 3.测试方法必须以 test 开头

3. pytest测试用例的运行方式
1)主函数运行方式 pytest.main()
pytest.main( ) 是一个非常灵活的方法,它允许你在Python脚本中直接调用pytest来运行测试用例。这种方式特别适合在需要自动化执行测试或者与其他工具集成时使用。
- 运行全部符合 pytest 规则的测试用例
import pytest
if __name__ == '__main__':
pytest.main()
符合 pytest 规则的测试用例

运行结果

- - - 指定模块运行
可以通过传递参数给 pytest.main() 来指定要运行的特定测试文件或目录
举例:
pytest.main(['-vs', './testcase/Login/test_login.py'])
各种参数详解:
| -s | 输出调试信息,包括代码当中print打印信息 |
| -v | 显示更加详细的信息,比如每个测试用例的完整名称和状态(通过还是失败) |
| -vs | 这是 -v 和 -s 的组合,既显示详细信息又不捕获标准输出 |
| -n | 支持多进程或分布式运行测试用例,可以显著提高测试速度,特别是在大型项目中 |
| –reruns | 允许设置测试用例失败重跑次数,–reruns=2,对于不稳定或偶尔失败的测试特别有用 |
| -x | 遇到错误的结果即刻停止运行 |
| –maxfail | 可以设置失败几次后停止运行,–maxfail=2(失败两次) |
- -vs输出结果

-n 参数使用方法 pytest.main([‘-vs’, ‘-n’, ‘3’, ‘./testcase/’])
注:若执行失败可能是未安装 pytest-xdist 插件,以下为安装命令
pip install pytest-xdist
未使用时执行速度

使用后执行速度

- - - 指定文件夹下的测试用例
这会递归地查找指定文件夹及其子文件夹中的所有测试文件并运行它们
pytest.main(['-vs', './testcase/'])

@pytest.mark 常见用法
| 标记类型 | 语法 | 使用场景 | 注意事项 |
|---|---|---|---|
| skip | @pytest.mark.skip(reason=“说明”) | 无条件跳过测试 | 始终跳过,不执行测试 |
| skipif | @pytest.mark.skipif(condition(条件), reason=“说明”) | 条件满足时跳过 | condition 为 True 时跳过 |
| xfail | @pytest.mark.xfail(reason=“说明”) | 预期会失败的测试 | 失败不算错,成功算惊喜 |
| parametrize | @pytest.mark.parametrize(“参数名”, [值列表]) | 参数化测试 | 实现数据驱动测试 |
| usefixtures | @pytest.mark.usefixtures(“fixture_name”) | 强制使用固件 | 类或方法级别应用fixture |
| 自定义分组 | @pytest.mark.组名 | 测试分类 | 需在 pytest.ini 中声明 |
| 目的 | 命令 |
|---|---|
| 运行特定分组 | pytest -m “smoke” |
| 排除某分组 | pytest -m “not smoke” |
| 组合条件 | pytest -m “smoke and not xfail” |
| 查看所有标记 | pytest --markers |
改变测试用例的执行顺序 使用@pytest.mark.run(order=…) 装饰器
import pytest
class TestLogin:
@pytest.mark.run(order=2)
def test_case01(self):
print('第2个')
@pytest.mark.run(order=3)
def test_case02(self):
print('第3个')
@pytest.mark.run(order=1)
def test_case03(self):
print('第1个')
若执行失败可能是未安装 pytest-ordering 插件,以下为安装命令
pip install pytest-ordering
- 执行结果

2)命令行运行
pycharm打开终端

- 全部运行 pytest

- 指定模块运行 pytest -vs ./testcase/user/user_test.py

- 指定文件夹下的测试用例 pytest -vs ./testcase

- -n 多进程或分布式运行测试用例 pytest -vs ./testcase -n 3

3)通过读取 pytest.ini 配置文件运行(pytest.ini作用:约定或者改变pytest默认的行为)
pytest.ini是pytest框架的核心文件,文件名及后缀为固定写法,不可变更

在根目录创建 pytest.ini 文件(一般存放在项目的根目录下)
pytest.ini 编码格式,必须为ANSI格式,在pytest.ini文件不可以加上中文(以下为常用固定配置内容)
[pytest]
# 指定测试用例的搜索路径
testpaths = ./testcase
# 指定测试文件的命名规则
python_files =
test_*.py
*_test.py
# 指定测试类的命名规则
python_classes =
Test*
*Test
# 指定测试方法/函数的命名规则
python_functions = test_*
# 生成精美的测试报告
addopts = --alluredir=./report/temp -vs --clean-alluredir -p no:warnings
# 日志配置(可选)
log_cli = true
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)8s] %(name)s: %(message)s
log_cli_date_format = %Y-%m-%d %H:%M:%S
运行规则:不管你是通过主函数运行还是通过命令行运行,它都会去读取pytest.ini配置文件
4. pytest测试用例分组执行(冒烟测试)
- 核心方案:使用 @pytest.mark
1)定义分组标记(在测试用例上添加分组标记)
此处将测试用例分为三组 { smock,regression,未分组 }
import pytest
@pytest.mark.smoke
def test_login():
assert True
@pytest.mark.regression
def test_user_create():
assert True
def test_normal_case():
assert True
2)在 pytest.ini 中写入分组配置(必写)
注意 pytest.ini 为 [pytest] markers
[pytest]
markers =
smoke: 冒烟测试
regression: 回归测试
slow: 慢速测试
3)分组执行命令(主函数 / 命令行)
- 只运行冒烟测试:
pytest.main(['-v', '-m', 'smoke'])
- 运行非冒烟测试:
pytest.main(['-v', '-m', 'not smoke'])
- 组合条件:
---- 运行冒烟测试且不是慢速的
pytest.main(['-v', '-m', 'smoke and not slow'])
pytest.main(['-v', '-m', 'smoke or not slow'])
4)多标记使用
@pytest.mark.smoke
@pytest.mark.regression
def test_critical_path():
assert True
5)查看所有标记
pytest --markers
5. pytest测试用例跳过执行
1)无条件跳过
@pytest.mark.skip - - - 原因可写可不写,写了便于维护
@pytest.mark.skip(reason="暂未实现")
def test_case02(self):
print('第3个')
2)有条件跳过
@pytest.mark.skipif - - - 后面写条件
import sys
import pytest
@pytest.mark.skipif(sys.version_info < (3, 8), reason="需要Python 3.8+")
def test_skip_if():
assert True
@pytest.mark.skipif(len("hello") != 5, reason="长度不匹配")
def test_another():
assert True

486

被折叠的 条评论
为什么被折叠?



