Pytest用例间参数传递的两种实现方式示例

前言

我们在做接口自动化测试的时候,会经常遇到这种场景:接口A的返回结果中的某个字段,是接口B的某个字段的入参。如果是使用postman,那我们可以通过设置后置变量,然后在需要使用的地方通过{{}}的方式来进行调用。但是如果是使用自己写的测试框架中要如何实现呢?我想到的是如下三种方法。

首先说明一下,以下三种方式均是通过python + pytest来实现的

一、通过conftest创建全局变量

conftest.py文件是pytest框架中很有用的一个东西,首先看下官方文档中的解释:

大概意思就是说,conftest.py文件供整个用例目录(conftest.py文件可以有多个,并且只在当前package下生效)使用而无需导入,也就是说在用例目录是conftest中的信息是公用的,例如:

1

2

3

4

5

6

7

8

9

10

11

12

a/conftest.py:

    def pytest_runtest_setup(item):

        # called for running each test in 'a' directory

        print("setting up", item)

  

a/test_sub.py:

    def test_sub():

        pass

  

test_flat.py:

    def test_flat():

        pass

运行后的结果:

pytest test_flat.py --capture=no  # will not show "setting up"

pytest a/test_sub.py --capture=no  # will show "setting up"

而我们就可以通过conftest + fixture函数来实现我们想要的效果了,具体代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

# conftest.py

  

# 定义一个全局变量,用于存储内容

global_data = {}

  

@pytest.fixture

def set_global_data():

    """

    设置全局变量,用于关联参数

    :return:

    """

  

    def _set_global_data(key, value):

        global_data[key] = value

  

    return _set_global_data

  

@pytest.fixture

def get_global_data():

    """

    从全局变量global_data中取值

    :return:

    """

  

    def _get_global_data(key):

        return global_data.get(key)

  

    return _get_global_data

简单说一下实现逻辑:

  1. 首先定义一个变量global_data用于接收存储用例返回的结果
  2. set_global_data和get_global_data两个fixture方法顾名思义,set方法是往global_data中存数据,get方法是从global_data中取数据

方法实现了,具体应该怎么使用呢?如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# test_get_set.py

  

import requests

import pytest

  

  

  

def test_set(set_global_data):

    res = requests.get("http://www.baidu.com")

    status_code = res.status_code

    logger.info(f"请求返回状态码:{status_code}")

    set_global_data("status_code", status_code)

  

  

def test_get(get_global_data):

    data = get_global_data("status_code")

    logger.info(f'通过get_global_data方法获取的值:{data}')

  

  

if __name__ == '__main__':

    pytest.main(['-sv''test_get_set.py'])

返回结果:

test_get_set.py::test_set PASSED

2021-12-24 17:58:37.642 | INFO     | cases.test_get_set:test_set:19 - 请求返回状态码:200

2021-12-24 17:58:37.643 | INFO     | cases.test_get_set:test_get:25 - 通过get_global_data方法获取的值:200

test_get_set.py::test_get PASSED

============================== 2 passed in 0.06s ===============================

通过这种方式,便实现了用例间的参数传递问题。

在实际工作中,因为涉及到的接口、用例会很多,所以可以根据需要使用不同的conftest进行管理。并且存储的数据结构也需要进行规范区分,如使用方法名作为字典的key。

二、使用tmpdir_factory方法

第二种方法,是使用pytest的tmpdir和tmpdir_factory两个夹具函数,同样是通过conftest文件来实现。仍然是先来看下官方文档针对这两个方法的说明:

简单来说,这两个方法的作用就是为每个测试方法创建一个临时目录用于存储自定义的文件,这个临时目录会默认保存3个sessions,之后就会按照创建的顺序删除旧的目录。看下官方的例子:

1

2

3

4

5

6

7

# content of test_tmpdir.py

def test_create_file(tmpdir):

    = tmpdir.mkdir("sub").join("hello.txt")

    p.write("content")

    assert p.read() == "content"

    assert len(tmpdir.listdir()) == 1

    assert 0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

# contents of conftest.py

import pytest

  

  

@pytest.fixture(scope="session")

def image_file(tmpdir_factory):

    img = compute_expensive_image()

    fn = tmpdir_factory.mktemp("data").join("img.png")

    img.save(str(fn))

    return fn

  

  

# contents of test_image.py

def test_histogram(image_file):

    img = load_image(image_file)

    # compute and test histogram

我在实际项目中的使用:

仍是在conftest.py文件中自定义一个夹具函数,返回结果是一个元组,p是tmpdir_factory方法返回的对象,转为字符串之后就是文件存储的路径。

自定义一个名为“apitest-tmp-dir”的文件夹用于存储文件

1

2

3

4

5

6

7

8

9

10

# conftest.py

  

@pytest.fixture

def tmp_factory(tmpdir_factory):

    """

    生成临时目录

    """

    = tmpdir_factory.mktemp('apitest-tmp-dir')

    logger.info("当前临时文件的目录为:" + str(p))

    return p, str(p)

在测试方法中的使用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

# test_get_set.py

  

import requests

import pytest

import json

  

  

def test_set(tmp_factory):

    res = requests.get("http://www.baidu.com")

    status_code = res.status_code

    logger.info(f"返回状态码:{status_code}")

  

    logger.debug(tmp_factory)

    # 创建test_set.txt文件

    = tmp_factory[0].join("test_set.txt")

    # 将需要的内容写入到文件中

    a.write({"status_code": status_code})

     

    # 使用read()方法获取文件中的内容

    logger.debug(a.read())

  

  

  

if __name__ == '__main__':

    pytest.main(['-sv''test_get_set.py'])

返回结果: 

test_get_set.py::test_set 2021-12-24 18:24:39.292 | INFO     | cases.conftest:tmp_factory:150 - 当前临时文件的目录为:/private/var/folders/_f/1d0lt83x1599bf6mcfppbwp40000gn/T/pytest-of-j/pytest-19/apitest-tmp-dir0

2021-12-24 18:24:39.347 | INFO     | cases.test_get_set:test_set:32 - 返回状态码:200

2021-12-24 18:24:39.347 | DEBUG    | cases.test_get_set:test_set:34 - (local('/private/var/folders/_f/1d0lt83x1599bf6mcfppbwp40000gn/T/pytest-of-j/pytest-19/apitest-tmp-dir0'), '/private/var/folders/_f/1d0lt83x1599bf6mcfppbwp40000gn/T/pytest-of-j/pytest-19/apitest-tmp-dir0')

2021-12-24 18:24:39.348 | DEBUG    | cases.test_get_set:test_set:38 - {'status_code': 200}

PASSED

============================== 1 passed in 0.07s ===============================

创建的文件:

可以看到,tmpdir_factory会自动为我们创建一个目录,名字是`tmp_factory`方法中自定义的名称后面加0,同时它的上级目录会自动从pytest-0递增

说下这个办法的优缺点:

  • 先说优点,这种数据存储是直接写入到文件,因此即使运行结束后也可以访问,而不像第一种方法存储的内容会随着用例运行的结束而消失
  • 再说缺点,因为这个临时目录最多只能保存3个,因此如果用例很多时,那么就可能存在文件被自动删除的风险。不过这个貌似可以通过修改默认配置来解决,可以继续研究下。
  • 缺点二,上面的例子中,直接通过a.read()就访问到了文件中的内容,这是因为内容的存储与读取全是在一个方法内,因此可以直接调用。如果是A方法存结果,在B中需要读取,那么便不能直接使用read()方法了(因为每个方法都会创建一个目录,并且默认的读取地址都是这个方法自己创建的目录)。就需要我们自己去单独封装一个读取文件的方法了,实现起来也不难而且tmpdir本身的这些方法也是对os.path一些方法的二次封装。

话说回来,都需要我自己去封装一个读取文件的方法了,为啥不干脆把读、写都自己来做呢?这样是否删除文件、删除几个、什么时候删除就完全由自己定义了啊,貌似会更方便。。。。。三、总结

综上所述,大家应该对这两种方法都有了一些了解,核心都是通过pytest的conftes.py文件来实现的。

 

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/761384.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[LLM]大模型基础知识点--大模型与LLM

1、什么是大模型? 定义:在机器学习领域,"大模型"通常指的是拥有大量参数的深度学习模型。这些模型通常由数十亿甚至数千亿个参数组成。 特点:由于参数众多,这些模型能够从大量数据中学习复杂的模式和关系。…

OJ : 1087 : 获取出生日期(多实例测试)

题目描述 输入某人的18位身份证号,输出其出生日期。 输入 多实例测试。首先输入一个整数n,表示测试实例的个数,然后是n行,每行是一个18位身份证号。 输出 对于输入的每个身份证号,输出一行,即其对应的…

SpringMVC 的运行流程

Spring MVC 是一个基于 MVC 设计模式的 Web 框架,它提供了一种优雅的方式来构建 Web 应用程序,将应用程序的不同部分分离开来,以便更好地管理和维护。了解 Spring MVC 的运行流程对于理解它的工作原理以及在实际项目中的应用非常重要。 1. 请…

银行卡账户交易异常已被限制部分功能,怎么办?

文章目录 I 解决方案1.1 限制原因1.2 防范1.3 案例1.4 用卡安全小知识II 个人账户收款监管规则III 反诈提醒I 解决方案 处理非柜面交易限制,只能到开户行柜台申请解除。异地卡的,需要联系开户行,提供相关资料。有些地方银行的,比如长沙银行,可以使用线上柜台进行审核。先到…

# termux连接云服务器

termux使用 pkg install openssh 连接服务器 ssh root39.100.181.23 安装postgres

不满足软件包要求‘transformers==4.30.2‘, ‘sse-starlette

transformers4.30.2支持的SSE-Starlette版本是0.14.0

Flume入门概述及安装部署

目录 一、Flume概述1.1 Flume定义1.2 Flume基础架构 二、Flume安装部署 一、Flume概述 1.1 Flume定义 Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。Flume基于流式架构,灵活简单。 1.2 Flume基础…

Python实现计算复读次数(附带源码)

在Python中,可以使用以下几种方法计算复读次数: 方法一:使用count()函数 count()函数用于统计字符串中某个字符或子字符串出现的次数。 示例: Python # 计算字符串中 "a" 出现的次数 count "hello world&quo…

13、Deconstructing Denoising Diffusion Models for Self-Supervised Learning

简介 研究了最初用于图像生成的去噪扩散模型(DDM)的表示学习能力 解构DDM,逐步将其转变为经典的去噪自动编码器(DAE) 探索现代ddm的各个组成部分如何影响自监督表征学习 结论: 只有很少的现代组件对于学习良好的表示是至关重要的,而其他许多…

Linux gcc二进制下载地址

Index of /download/x86_64/releases 待验证: export PATH$HOME/YOURS/gcc-5.4.0/bin:$PATH export LD_LIBRARY_PATH$HOME/YOURS/gcc-5.4.0/lib:$HOME/YOURS/gcc-5.4.0/lib64:$LD_LIBRARY_PATH

【算法刷题day2】Leetcode:977.有序数组的平方、 209.长度最小的子数组、59.螺旋矩阵II

Leetcode:977.有序数组的平方 文档讲解:[代码随想录] 题目链接:977.有序数组的平方 状态:ok 题目: 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序…

web蓝桥杯真题:心愿便利贴

代码及注释&#xff1a; <!-- TODO 待修改的代码 --> <div class"card" :class"item.css" v-for"(item,index) in wishList" :key"index"><div class"header"><img class"close" click&quo…

智能ai写作神器,推荐5个ai在线写作生成器

智能AI写作神器&#xff0c;是不是听起来就很神奇&#xff1f;它们可以帮助我们省去无尽的头疼和煎熬&#xff0c;让我们的文字轻松流畅&#xff0c;幽默风趣。今天&#xff0c;我要向大家推荐五款AI在线写作生成器&#xff0c;让我们一起来看看吧&#xff01; 第一个&#xff…

训练YOLOv9-S

1. YOLOv9-S网络结构 1.1 改前改后的网络结构&#xff08;参数量、计算量&#xff09;对比 修改前调用的yolo.py测试的yolov9.yaml的打印网络情况&#xff0c;包含参数量、计算量 修改后调用的yolo.py测试的yolov9.yaml的打印网络情况&#xff0c;包含参数量、计算量 1.2 …

flutter实现视频播放器,可根据指定视频地址播放、设置声音,进度条拖动,下载等

需要装依赖&#xff1a; gallery_saver: ^2.3.2video_player: ^2.8.3 实现代码 import dart:async; import dart:io;import package:flutter/material.dart; import package:gallery_saver/gallery_saver.dart; import package:path_provider/path_provider.dart; import pac…

Revit2020也能玩衍生式设计?

Revit2021新增的一个好玩功能就是衍生式设计&#xff0c;但是Autodesk2021系列的激活目前还比较麻烦&#xff0c;尤其是要装多款2021软件的时候&#xff0c;注册机用起来还挺烦人的&#xff0c;于是&#xff0c;为了省事&#xff0c;我把GenerativeDesignRevit节点包扔到了Dyna…

大模型应用开发:手把手教你部署并使用清华智谱GLM大模型

部署一个自己的大模型&#xff0c;没事的时候玩两下&#xff0c;这可能是很多技术同学想做但又迟迟没下手的事情&#xff0c;没下手的原因很可能是成本太高&#xff0c;近万元的RTX3090显卡&#xff0c;想想都肉疼&#xff0c;又或者官方的部署说明过于简单&#xff0c;安装的时…

邮箱合法性的判断与indexOf()==-1的解释

判断邮箱格式输入的对错&#xff0c;简化为是否有“.”&#xff0c;&#xff0c;前后是否有字符。 需要用到字符串的遍历比对&#xff0c;字符串的抓取与赋值。 代码主体&#xff1a; public class youpanduanyouxiangshifouhefa {//判断输入的邮箱是否合法public static vo…

Java设计模式 | 工厂方法模式

工厂方法模式 针对简单工厂模式案例中的缺点&#xff0c;使用工厂方法模式就可以完美的解决&#xff0c;完全遵循开闭原则。简单工厂模式只有一个工厂类&#xff0c;负责创建所有产品&#xff0c;如果要添加新的产品&#xff0c;就需要修改工厂类的代码。而工厂方法模式引入了…

Halcon ORC字符识别

OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;是通过使用OCR工具实现的。Halcon提供了一些用于进行字符识别的函数和工具&#xff0c;可以帮助用户实现文本的自动识别和提取。 read_ocr_class_mlp&#xff1a;用于读取一个经过训练好的OC…