首页 > 其他分享 >pytest测试框架中数据分离以及测试用例参数化

pytest测试框架中数据分离以及测试用例参数化

时间:2023-09-20 14:44:06浏览次数:46  
标签:框架 resp pytest assert json 测试用例 expected

在进行测试自动化过程中,一个重要的最佳实践就是实现测试脚本和测试数据的分离。本文将涉及2个主题,一个是在pytest中如何实现测试用例脚本数据的分离,测试用例如何读入测试数据;二是在pytest中如何实现测试用例参数化。这两点是有区别的,如下图:

flowchart LR TC[测试脚本] -->|读取外部测试数据| B(测试用例) C[测试脚本] --> |参数| D(参数迭代每个测试用例)

前者处理的是测试用例的数据读取,针对的是单一测试用例;后者是针对具有相同测试逻辑的测试用例,叠加参数,这样形成多个测试用例。

测试数据的读取

使用自定义的函数读取

下面的示例在自定义的utils模块中的 load_json_data 方法来读取外部数据文件, 外部数据文件以json格式存储。使用的 shared_datadir 是一个fixture, 来自pytest插件 pytest-datadir, 用于定义外部数据文件的存放的路径。

from utils import utils

def test_post_json(api, shared_datadir):
    filepath = (shared_datadir / 'example.json')
    resp = api.post("/post", headers={"Content-Type": "application/json"}, json=utils.load_json_data(filepath))
    resp_json = resp.json()
    assert resp.status_code == 200, "Response Code"
    assert len(resp_json['json']['sites']) == 3, "Response JSON Site"
    assert resp_json['json']['sites'][0]['name'] == "菜鸟"

utils.py

def load_json_data(filepath):
    """
    :param filepath: The full file path.
    :return: A JSON Object.
    """
    with open(filepath, mode='r', encoding='utf-8') as f:
        data = json.load(f)
    return data

使用自定义的fixture来处理

下面的示例自定义了一个 load_tc_yaml_data 的 fixture, 同时可以在测试用例上通过装饰器提供测试用例的外部数据的文件名。这样的好处可以把测试数据文件名写在测试用例外面,不需要hardcode在测试用例的逻辑代码中。该方法实现也同样需要pytest的插件pytest-datadir支持测试数据路径的解析。使用数据时和fixture使用一致, 函数名即代表数据的返回。

@pytest.mark.data_file('test_get_with_param_in_url.yml')
def test_httpbin_basic(api, load_tc_yaml_data):
    resp = api.get("/headers")
    host = resp.json()["headers"]["Host"]
    assert resp.status_code == 200, "Response Code"
    assert host == "httpbin.org", "Response Host"

    resp = api.get("/user-agent")
    resp_json = resp.json()
    assert resp.status_code == 200, "Response Code"
    assert resp_json["user-agent"] == "python-requests/2.31.0"

    resp = api.get("/get")
    resp_json = resp.json()
    assert resp.status_code == 200, "Response Code"
    assert resp_json["args"] == {}

    resp = api.get("/get", params=load_tc_yaml_data)
    resp_json = resp.json()
    assert resp.status_code == 200, "Response Code"
    assert resp_json["args"] == {'a': '1', 'b': '2'}

    resp = api.get("/cookies/set?name=value")
    resp_json = resp.json()
    assert resp.status_code == 200, "Response Code"
    assert resp_json["cookies"]["name"] == "value"

conftest.py中定义的fixture, 会读取装饰器data_file的值,然后解析路径,读取文件内容并返回。

@pytest.fixture
def load_tc_yaml_data(shared_datadir, request) -> dict:
    marker = request.node.get_closest_marker('data_file')
    data_path = (shared_datadir / marker.args[0])
    with open(data_path, 'r', encoding='utf-8') as yaml_file:
        data = yaml.safe_load(yaml_file)
    return data

测试用例参数化

使用@pytest.mark.parametrize参数化函数

内置的 pytest.mark.parametrize 装饰器可以对测试函数的参数进行参数化。 以下是测试函数的典型示例,该函数实现检查特定输入是否会产生预期输出:

import pytest

@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, expected):
    assert eval(test_input) == expected

这里, @parametrize 装饰器定义了三个不同的 (test_input,expected) 元组,形成三个测试用例。

使用@pytest.mark.parametrize参数化类

@pytest.mark.parametrize("n,expected", [(1, 2), (3, 4)])
class TestClass:
    def test_simple_case(self, n, expected):
        assert n + 1 == expected

    def test_weird_simple_case(self, n, expected):
        assert (n * 1) + 1 == expected

另外一种写法

pytestmark = pytest.mark.parametrize("n,expected", [(1, 2), (3, 4)])

class TestClass:
    def test_simple_case(self, n, expected):
        assert n + 1 == expected

    def test_weird_simple_case(self, n, expected):
        assert (n * 1) + 1 == expected

标记单个失败用例

@pytest.mark.parametrize(
    "test_input,expected",
    [("3+5", 8), ("2+4", 6), pytest.param("6*9", 42, marks=pytest.mark.xfail)],
)
def test_eval(test_input, expected):
    assert eval(test_input) == expected

堆叠参数(参数进行笛卡尔积)

@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_foo(x, y):
    pass

这将运行测试,参数设置为 x=0/y=2、x=1/y=2、x=0/y=3 和 x=1/y=3,按照装饰器的顺序耗尽参数 。

标签:框架,resp,pytest,assert,json,测试用例,expected
From: https://www.cnblogs.com/herbert/p/17717284.html

相关文章

  • 支持JDK19虚拟线程的web框架,之五(终篇):兴风作浪的ThreadLocal
    欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos本篇概览本篇是《支持JDK19虚拟线程的web框架》系列的第五篇,也是全系列的终篇,之前的文章实战、写代码、读源码,想必把大家累坏了,今天咱们开启聊天模式,畅谈虚拟线程中的一......
  • 框架分析(3)-Vue.js
    (框架分析(3)-Vue.js)专栏介绍link主要对目前市面上常见的框架进行分析和总结,希望有兴趣的小伙伴们可以看一下,会持续更新的。希望各位可以监督我,我们一起学习进步。Vue.jsVue.js是一种用于构建用户界面的渐进式JavaScript框架。它是一个轻量级的框架,通过将视图层和状态层进行绑......
  • 数据分析方法论、流程和框架分别是什么?
     数据分析方法论、流程和框架是指在进行数据分析时所采用的一系列方法、步骤和结构化框架,旨在帮助数据分析人员更系统、有效地进行数据分析工作。下面将详细介绍数据分析方法论、流程和框架的概念、主要内容和实际应用。1.数据分析方法论:数据分析方法论是指在数据分析过程......
  • OpenHarmony AI框架开发指导
    OpenHarmonyAI框架开发指导一、概述1、功能简介AI业务子系统是OpenHarmony提供原生的分布式AI能力的子系统。AI业务子系统提供了统一的AI引擎框架,实现算法能力快速插件化集成。AI引擎框架主要包含插件管理、模块管理和通信管理模块,完成对AI算法能力的生命周期管理和按需......
  • 华为集成供应链流程框架
           ......
  • OpenHarmony AI框架开发指导
    一、概述1、功能简介AI业务子系统是OpenHarmony提供原生的分布式AI能力的子系统。AI业务子系统提供了统一的AI引擎框架,实现算法能力快速插件化集成。AI引擎框架主要包含插件管理、模块管理和通信管理模块,完成对AI算法能力的生命周期管理和按需部署。插件管理主要实......
  • 框架分析(2)-React
    (框架分析(2)-React)专栏介绍link主要对目前市面上常见的框架进行分析和总结,希望有兴趣的小伙伴们可以看一下,会持续更新的。希望各位可以监督我,我们一起学习进步。ReactReact是由Facebook研发的一个用于构建用户界面的JavaScript库。它采用了组件化的开发方式,通过将界面拆分成......
  • 02_实战项目Zlog日志框架
    Zlog日志注释控制日志打印//printf("appstart\n");printf("appstart\n");printf("appstart\n");//printf("appstart\n");printf("appstart\n");//printf("appstart\n");printf("appstart\n&quo......
  • CommonTK框架之Qt5配置cmake脚本
    源码获取CommonTKCMake配置打开下图的CMake脚本文件添加下面的代码SET(CTK_QT_VERSION5)SET(CMAKE_PREFIX_PATH${CMAKE_PREFIX_PATH}"C:/major/development/tools/qt/5.14/install/5.14./msvc2015_64")添加的脚本代码位置如下图C:/major/development/tools/q......
  • Android 大厂用 Jetpack Compose 框架用的多吗?
    前言如果一直关注JetpackCompose的发展的话,可以明显感受到2022年和2023年的JetpackCompose使用讨论的声音已经完全不一样了,2022年还多是观望,2023年就有很多团队开始采纳JetpackCompose来进行开发了。不过也有很多同学接触了下JetpackCompose,然后就放弃了。要么使用......