Pytest+requests进行接口自动化测试3.0(yaml配置文件 + Pytest框架基础知识)

一、自动化测试项目的目录结构

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

在这里插入图片描述

目录名称含义用途
.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框架-详解

一、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
在参考内容中,有与使用pytestyaml和selenium相关的实战项目信息。例如,在pytest non - python tests内容基础上做改动,使读取文件贴合自定义的yaml文件内容,精简代码并达到预期效果,还涉及处理request [^1]。 另外,有pytest - yaml - sanmu使用yaml进行API测试和Web测试的内容,给出了根据python版本web测试用例设计的yaml版Web测试用例示例,包括使用百度搜索的步骤,如获取浏览器驱动、设置隐式等待、访问百度页面、查找元素并进行输入和点击操作、截图以及退出等 [^3]。 还有pytest + yaml框架使用教程,涵盖框架功能介绍、启动步骤(包括源码下载、环境配置、启动mock接口服务、配置环境和项目信息等)、使用教程(如环境信息配置、token信息写入、执行用例目录文件配置、用例编写和执行入口等) [^4]。虽然未明确提及requests,但在pytest的应用场景中,常结合requests进行接口自动化测试 [^2]。 以下是一个简单的示例代码,展示如何结合pytestrequestsyaml和selenium: ```python import pytest import requests import yaml from selenium import webdriver # 读取yaml文件 def read_yaml(file_path): with open(file_path, &#39;r&#39;, encoding=&#39;utf-8&#39;) as f: return yaml.safe_load(f) # 示例接口测试 @pytest.mark.parametrize("test_case", read_yaml(&#39;api_test.yaml&#39;)) def test_api(test_case): url = test_case[&#39;url&#39;] method = test_case[&#39;method&#39;] if method == &#39;GET&#39;: response = requests.get(url) elif method == &#39;POST&#39;: data = test_case.get(&#39;data&#39;, {}) response = requests.post(url, json=data) assert response.status_code == test_case[&#39;expected_status&#39;] # 示例Web测试 @pytest.mark.parametrize("test_case", read_yaml(&#39;web_test.yaml&#39;)) def test_web(test_case): driver = webdriver.Chrome() try: for step in test_case[&#39;steps&#39;]: if &#39;get&#39; in step: driver.get(step[&#39;get&#39;]) elif &#39;find_element&#39; in step: by = step[&#39;find_element&#39;][&#39;by&#39;] value = step[&#39;find_element&#39;][&#39;value&#39;] element = driver.find_element(by, value) if &#39;send_keys&#39; in step[&#39;find_element&#39;][&#39;action&#39;]: element.send_keys(step[&#39;find_element&#39;][&#39;action&#39;][&#39;send_keys&#39;]) elif &#39;click&#39; in step[&#39;find_element&#39;][&#39;action&#39;]: element.click() elif &#39;get_screenshot_as_file&#39; in step: driver.get_screenshot_as_file(step[&#39;get_screenshot_as_file&#39;]) finally: driver.quit() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值