Pytest精通指南(26)钩子函数-依赖执行(pytest-dependency)


文章目录

      • 前言
      • 应用场景
      • 插件安装
      • 注意事项
      • 参数分析
      • 函数名称依赖实现方式
      • 类下函数路径实现方式
      • 通过设置别名指定依赖
      • 定义依赖范围
      • 作用于类
      • 作用于模块
      • 作用于包
      • 作用于会话
      • 拓展-非常重要


请添加图片描述

前言

pytest-dependency的主要用途是确保测试用例按照指定的依赖关系顺序执行。

在一个复杂的测试套件中,某些测试用例可能依赖于其他测试用例的结果或状态。

pytest-dependency允许明确地定义这些依赖关系,从而确保依赖项先执行,然后再执行依赖于此的测试用例。

这意味着我们可以指定某些测试用例必须在其他测试用例成功执行后才能运行。

通过这种方式,我们可以确保测试的执行顺序与依赖关系得到正确的处理。

应用场景

  • 有序的测试执行:当测试用例之间存在逻辑依赖关系时,需要确保它们按照正确的顺序执行。
    例如,一个测试用例可能设置了某些数据,而另一个测试用例依赖于这些数据。
  • 资源准备和清理:在某些情况下,可能需要首先准备一些资源(如数据库连接、文件、网络服务等),并在所有相关测试完成后进行清理。
    pytest-dependency可以帮助你确保资源准备和清理的顺序正确。
  • 条件测试:我们可能只想在满足特定条件时再执行某些测试用例。
    pytest-dependency可以基于其他测试用例的成功或失败来执行特定的测试。

插件安装

安装命令pip install pytest-dependency

官方文档: https://pytest-dependency.readthedocs.io/en/latest/index.html

请添加图片描述

注意事项

  • 误解依赖关系:有些人可能误解了 depends 参数的含义,认为它定义了测试用例的执行顺序,但实际上它定义的是依赖关系,而不是执行顺序。
    执行顺序仍由pytest的内部机制决定,但pytest-dependency插件会在必要时跳过或重新运行测试用例以满足依赖关系。

  • 错误的使用:如果不正确地使用pytest-dependency,可能会导致测试用例之间的耦合度过高,难以维护和扩展。
    因此,应谨慎使用依赖关系,确保它们确实是必要的。

  • 插件配置问题:如果没有正确配置pytest-dependency插件,例如未安装插件或未正确地在pytest命令中包含插件,那么依赖关系将不会生效。

  • 并发执行:如果使用pytest的并发执行功能(如-n参数),请确保依赖关系不会被打乱。
    pytest-dependencypytest 的并发执行功能可能不完全兼容,因此需要谨慎使用。

  • 测试隔离:尽量确保每个测试用例是独立的,不依赖于其他测试用例的结果。这样可以提高测试的健壮性和可复用性。

参数分析

@pytest.mark.dependency装饰器接受以下参数,其中最常用的是 depends:

  • depends: 这是一个字符串列表,指定了当前测试用例所依赖的其他测试用例的名称。
    只有当这些依赖项都成功执行时,当前测试用例才会被执行。

  • scope: 这个参数定义了依赖关系的范围。
    默认情况下,依赖关系是在整个测试会话中有效的。
    如果设置为"session", 它会覆盖默认行为。
    如果设置为"function", 则每个函数都会创建一个新的依赖上下文。

  • names: 这个参数允许你为依赖项指定一个自定义名称,这在某些情况下可能很有用,特别是当你有多个依赖项并希望使日志或报告更清晰时。

函数名称依赖实现方式

示例代码

python">import pytest# 模拟数据库
db = {}# 模拟注册
@pytest.mark.dependency()
def test_signup():assert len(db.keys()) == 0db.setdefault("username", "root")db.setdefault("password", "1234")# 模拟登录
@pytest.mark.dependency(depends=["test_signup"])
def test_login():# 依赖于 test_signup 的测试用例assert db.get("username") == "root"assert db.get("password") == "1234"

被依赖的测试用例执行成功结果

请添加图片描述

被依赖的测试用例执行失败结果

请添加图片描述

类下函数路径实现方式

示例代码

python">import pytestclass TestCase:@pytest.mark.dependency()def test_01(self):assert False@pytest.mark.dependency(depends=["TestCase::test_01"])def test_02(self):assert False

执行结果

请添加图片描述

通过设置别名指定依赖

示例代码

python">import pytest# 模拟数据库
db = {}# 模拟注册
@pytest.mark.dependency(name="1")
def test_signup():assert len(db.keys()) == 0db.setdefault("username", "root")db.setdefault("password", "1234")def test_03():assert True# 模拟登录
@pytest.mark.dependency(depends=["1"])
def test_login():# 依赖于 test_signup 的测试用例assert db.get("username") == "root"assert db.get("password") == "1234"class TestCase:@pytest.mark.dependency("name")def test_01(self):assert False@pytest.mark.dependency(depends="name")def test_02(self):assert False

执行结果

请添加图片描述

定义依赖范围

从官方说明中我们看到scope可以接受四种参数定义的类型:

  • session
  • package
  • module
  • class

请添加图片描述

作用于类

scope=“class”

  • 作用于所属类,外部类不会被关联

示例代码

python">import pytestclass TestCase1:@pytest.mark.dependency()def test_01(self):assert Falseclass TestCase2:@pytest.mark.dependency(scope="class")def test_01(self):assert True@pytest.mark.dependency(depends=["test_01"], scope="class")def test_02(self):assert True

执行结果

请添加图片描述

作用于模块

scope=“module”

  • 不传递scope参数,即默认参数是module,作用于当前py文件
  • 只会查找当前文件的符合条件的文件名,类里同名的方法不会被依赖

示例代码

python">import pytest@pytest.mark.dependency()
@pytest.mark.xfail(reason="模拟失败")
def test_fail():print("进入module::test_fail函数")assert Falseclass TestCase1:@pytest.mark.dependency()def test_01(self):assert Falseclass TestCase2:@pytest.mark.dependency()def test_fail(self):print("进入TestCase2::test_fail函数")assert True@pytest.mark.dependency(depends=["test_fail"])def test_02(self):assert True

执行结果

请添加图片描述

作用于包

scope=“package”

  • 作用于当前目录同级的依赖函数,跨目录无法找到依赖的函数。

test_case_01.py示例代码

python">import pytestclass TestCase1:@pytest.mark.dependency(scope="class")def test_01(self):print('测试用例01')assert 1 == 1@pytest.mark.dependency(depends=['test_01'], scope="class")def test_02(self):print('测试用例02依赖于测试用例01')assert True

test_case_02.py示例代码

python">import pytestclass TestCase2:@pytest.mark.dependency(depends=['testcase/test_case_01.py::TestCase1::test_02'],scope="package")def test_03(self):print('测试用例03依赖于统计目录下test_case_01.py的02')assert True

执行结果

请添加图片描述

作用于会话

scope=“session”

  • 作用域全局,可跨目录调用。但被依赖的用例必须先执行,否则用例会执行跳过!

testcase/test_case_01.py示例代码

python">import pytestclass TestCase1:@pytest.mark.dependency(scope="class")def test_01(self):print('测试用例01')assert 1 == 1@pytest.mark.dependency(depends=['test_01'], scope="class")def test_02(self):print('测试用例02依赖于测试用例01')assert True

testcase/test_case_02.py示例代码

python">import pytestclass TestCase2:@pytest.mark.dependency(depends=['testcase/test_case_01.py::TestCase1::test_02'],scope="package")def test_03(self):print('测试用例03依赖于统计目录下test_case_01.py的02')assert True

testcase2/test_case_03.py示例代码

python">import pytestclass TestCase3:@pytest.mark.dependency(depends=['testcase/test_case_02.py::TestCase2::test_03'],scope="session")def test_04(self):print('测试用例04依赖于非同级目录下test_case_02.py的03')assert True

执行结果

请添加图片描述

拓展-非常重要

  • 当使用 pytest.mark.parametrize 对测试用例进行参数化时,每个参数组合都会产生一个独立的测试用例实例,每个实例都有一个唯一的节点ID(nodeid),这个ID包含了测试用例的路径和参数值。
  • 因此,如果依赖的上下文测试用例使用了参数化,那么仅仅通过测试函数的方法名来建立依赖关系是不够的,因为同一个测试函数可能会有多个不同的实例,每个实例的节点ID都是唯一的。
  • 为了解决这个问题,pytest-dependency 插件支持使用节点ID来建立依赖关系,而不仅仅是测试函数的方法名。你可以通过传递节点ID数组来指定依赖关系,而不是简单地传递方法名。

示例代码

python">import pytest@pytest.mark.dependency()
@pytest.mark.parametrize('data', [1])
def test_a(data):# data = 1assert data == 1@pytest.mark.dependency(depends=['test_a'])
def test_d():assert True@pytest.mark.dependency(depends=['test_d'])
def test_b():assert 'ooo' == 'ooo'@pytest.mark.dependency(depends=['test_b'])
def test_c():assert 'lll' is 'lll'

执行结果-未指定参数化改变的node信息

请添加图片描述

执行结果-指定参数化改变的node信息

请添加图片描述


http://www.ppmy.cn/ops/23068.html

相关文章

C语言内存函数及模拟实现

之前写的字符函数都只针对字符串,而内存函数是针对内存的,不在乎内存里面是什么。 目录 memcpy函数介绍模拟实现 memmove函数介绍模拟实现 memset函数介绍 memcmp memcpy 函数介绍 void * memcpy ( void * destination, const void * source, size_t n…

Qt笔记-解决VS中.h文件新增Q_OBJECT或继承QObject后编译报错问题

原因是.h中某类添加Q_OBJECT宏以继承QObject后就需要使用Qt的moc工具生成对应的moc_xxx.cpp文件。 所以VS报错,就是缺少这个。所以使用Qt的moc生成如下: moc xxxx.h -o moc_xxxx.cpp 将此文件放到vs工程的generated files目录中,如果报#in…

将本地.mp4推流成rtsp流?(windows)

概述 如何在本地机器上进行rtsp推流整个操作? 1.软件安装 1. 推流-ffmpeg下载 从官网下载windows版本,该版本已经编译好了 放到C:下找一个目录解压,我放到C:\ffmpeg-7.0-essentials_build\进入系统环境变量设置:将…

Python Flask Web教程:make_response的详细用法

在 Flask 中,make_response 是一个非常实用的函数,它可以用来构造响应对象。下面是 make_response 函数的详细用法: 基本用法 在 Flask 中,make_response 可以用来从返回的数据中创建一个响应对象。它接受几种不同类型的参数,并返回一个 Response 对象。 from flask im…

国内外知名数据防泄漏DLP软件推荐|公司防泄密软件哪几个好用?

随着科技不断进步和企业业务不断发展,越来越多的公司开始重视内部数据安全,从简单的防火墙当专业的数据防泄漏软件,企业数据安全意识也从防止外部攻击逐渐转向内部泄密防护。 数据泄露防护(Data loss prevention)是一…

第三弹:JavaScript 学习记录

目录 1.1. 了解 1.1.1. 为什么学习JavaScript 1.1.2. JavaScript简介 1.1.3. JavaScript / ECMAScript 1.1.4. JavaScript使用方式 1.1.5. JavaScript输出 1.1.6. JavaScript语句 1.1.7. JavaScript注释 1.1.8. JavaScript变量及常量 1.1.9. JavaScript数据类型 1.1.…

matlab新手快速上手6(引力搜索算法)

本文根据一个较为简单的matlab引力搜索算法框架详细分析蚁群算法的实现过程,对matlab新手友好,源码在文末给出。 引力搜索算法简介: 引力搜索算法是一种启发式优化算法,最初于2009年由伊朗的Esmat Rashedi、Hossein Nezamabadi-p…

场外个股期权开户新规及操作方法

场外个股期权开户新规 场外个股期权开户新规主要涉及对投资者资产实力、专业知识、风险承受能力和诚信记录的要求。以下是根据最新规定总结的关键要点: 来源/:股指研究院 资产门槛:投资者需具备一定的资产实力,确保在申请开户前…

uniapp 对接facebook第三方登录

1.登录facebook开发者中心,打开我的应用页面在这里插入图片描述 2.创建应用 3.选择类型 4.填写信息 5.添加登录 6.添加平台 安卓密钥生成【需要 Java 环境!!! 和 openssl库】 Google Code Archive 的 Windows 版 openssl-for-windows OpenSSL 库 将openssl下载到…

企业微信hook接口协议,ipad协议http,发送大视频文件

发送大视频文件 参数名必选类型说明uuid是String每个实例的唯一标识,根据uuid操作具体企业微信send_userid是long要发送的人或群idisRoom是bool是否是群消息 请求示例 {"uuid":"1688853790xxx", //uuid 默认随机生成如果初始化传了id则用初始…

《QT实用小工具·三十九》仿 Windows10 画图3D 的颜色选择器, 但更加强大

1、概述 源码放在文章末尾 该项目实现了仿 Windows10 画图3D 的颜色选择器,功能更加丰富更加强大。 项目部分代码如下所示: import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import QtGraphicalEffects 1.15Item {id…

爬虫的实战应用之短信炸弹playwright现代网页测试工具

不讲废话,先上原理: 短信炸弹,也就是说持续对一个手机进行发送短信,实现的方式就是,利用某些网站的登录 ,注册的时候,发送短信验证码来实现。 如下图,其中有一个id为phone的输入框&a…

从零开始搭建SpringCloud

从零开始搭建Spring Cloud涉及到多个步骤和组件的配置。以下是一个大致的指南,帮助你逐步搭建Spring Cloud环境: 安装Java开发环境: 安装JDK(Java开发工具包)并确保环境变量配置正确。选择一个合适的IDE(集…

【MySQL】多表查询

1.多表查询分类讲解 1.1等值连接vs非等值连接 等值连接: SELECT student.name, class.name AS className FROM student, class WHERE student.class_id class.class_id; 非等值连接: SELECT a.name, a.salary, b.grade FROM teacher a, grades b WH…

RabbitMQ笔记(基础篇)

视频: MQ基础-01.RabbitMQ课程介绍_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1mN4y1Z7t9?p1&vd_sourced0ea58f1127eed138a4ba5421c577eb1 一、RabbitMQ简介 1.同步调用 优势:时效性强,等待结果后才返回 劣势&#xff1…

Linux网络配置以及DHCP

一、网络配置 将Linux主机接入到网络,需要配置网络相关设置 一般包括如下内容: 主机名 IP/netmask 路由:默认网关 DNS服务器 主DNS服务器 次DNS服务器 第三个DNS服务器 1.1显示网络接口的信息 ifconfig命令用于显示和配置网络接口的信…

http通讯协议之socket使用(思岚slam_mapper)

使用POSTman进行http通讯测试 Swagger UI (slamtec.com) HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web)服务器传输超文本到本地浏览器的传送协议。HT…

C#面:关于集合的几个选择题

1. 简述关于泛型以下说法错误的是 A)与传统类型相比,泛型集合更安全,但需要装箱和拆箱操作 B)List是通过索引访问集合中的元素 C)使用泛型类可以保证类型安全性 D)Dictionary可以通过键来访问集合元素 答案:A 2. 简述创建一个int泛型集合正…

13_Qt中的快捷键

Qt Creator的一些快捷操作: 项目管理: Build:以增量方式构建项目。Rebuild:重新构建项目。Clearn:清除项目构建过程中产生的所有中间文件。Run qmake:使用qmake/cmake重新构建项目。会重新执行UIC、MOC、…

数据结构--删除单链表中的某一个节点(时间复杂度控制为O(1))

题目描述🍗 只给定单链表中某个结点p(并非最后一个结点,即p->next!NULL)指针,删除该结点 思路分析🍗 结点不重要,,重要的是数据 不删自己,删除后面的结点: 1.把后面结点数据复制到当前 2.…