自动化测试-如何优雅实现方法的依赖

在复杂的测试场景中,常常会存在用例依赖,以一个接口自动化平台为例,依赖关系:

创建用例 --> 创建模块 --> 创建项目 --> 登录。

用例依赖的问题

• 用例的依赖对于的执行顺序有严格的要求,比如让被依赖的方法先执行。

• 一旦使用用例依赖,依赖的用例就无法单独执行了,按照用例的设计原则,每条用例都应该独立执行。

正确的做法

我们应该将依赖的操作封装成方法调用。如果能通过装饰器实现调用,那就很有趣了。

aomaker[1] 提供了这种装饰器的实现,seldom 进行了复刻,只是用法上有所不同。

类内部方法调用

我们可以在测试类下面,创建普通的方法。然后通过@dependent_func()装饰器调用他。

import seldom
from seldom.testdata import get_md5
from seldom.utils import cache, dependent_func


class DependentTest(seldom.TestCase):

    @staticmethod
    def user_login(username, password):
        """
        模拟用户登录,获取登录token
        """
        return get_md5(username+password)

    @dependent_func(user_login, username="tom", password="t123")
    def test_case(self,):
        """
        sample test case
        """
        token = cache.get("user_login")
        print("token", token)


if __name__ == '__main__':
    seldom.main(debug=True)
    cache.clear()

说明

这个例子涉及到不少知识点。

1.test_case() 用例依赖 user_login() 方法,通过 @dependent_func() 装饰器调用 user_login 方法。

2.user_login() 方法运行的时候需要参数(username、password),可以直接在 @dependent_func() 装饰器中设置参数:username=“tom”、 password=“t123”。

3.user_login() 方法运行运行完会生成 token, 保存于 cache中,通过 cache.get() 可以获取到token, 默认通过方法名user_login 作为key获取。

4.为了简化代码,生成token 是通过 get_md5() 根据传入的参数生成的一个 md5 值。

5.cache.clear() 用于清空缓存, 再次调用 user_login() 方法直接不执行,应为cache已经有上次的执行结果了。

执行日志

python zzz_demo.py
...
test_case (zzz_demo.DependentTest.test_case)
sample test case ... 2023-11-15 23:26:36 | INFO     | dependence.py | 🔗 <test_case> depends on <user_login>, execute.
2023-11-15 23:26:36 | INFO     | cache.py | 💾 Set cache data: user_login = 35e0ff9c4cba89998dda8255d0eb5408
2023-11-15 23:26:36 | INFO     | cache.py | 💾 Get cache data: user_login = 35e0ff9c4cba89998dda8255d0eb5408
token 35e0ff9c4cba89998dda8255d0eb5408
ok

----------------------------------------------------------------------
Ran 1 test in 0.005s

OK
2023-11-15 23:26:36 | SUCCESS  | runner.py | A run the test in debug mode without generating HTML report!
2023-11-15 23:26:36 | INFO     | cache.py | 💾 Clear all cache data

外部类方法依赖

•创建依赖方法

# common.py
from seldom.testdata import get_md5


class Login:

    @staticmethod
    def account_login(username, password):
        """
        模拟用户&密码登录,获取登录token
        """
        return get_md5(username+password)


login=Login()

•用例引用依赖方法

import seldom
from seldom.utils import cache, dependent_func
from common import Login # 方式1:引用依赖类
# from common import login  # 方式2:引用初始化好的类对象


class DependentTest(seldom.TestCase):


    @dependent_func(Login().account_login, key_name="token1", username="tom", password="t123")
    # @dependent_func(login.account_login, key_name="token1", username="tom", password="t123")
    def test_case(self):
        """
        Used tuple test data
        """
        token = cache.get("token1")
        print("token", token)


if __name__ == '__main__':
    seldom.main(debug=True)

说明

1.Common 类的account_login()方法可以不设置为静态方法,导入时需要类需要加括号:Common().user_login。 或者先初始化类对象login=Login() 再调用。

2.key_name 指定缓存的 key,如果指定为token1, 从缓存读取也使用这个cache.get(“token1”)。

多重方法依赖

复杂的场景当然是需要多重依赖的。

1.被依赖的方法可以进一步使用 dependent_func()装饰器进行多重复依赖。

查询模块 --> 查询项目 --> 登录

# common.py
from seldom.testdata import get_md5, get_int
from seldom.utils import cache, dependent_func

class Login:

    @staticmethod
    def account_login(username, password):
        """
        模拟用户&密码登录,获取登录token
        """
        return get_md5(username+password)

class DepFunc:

    @staticmethod
    @dependent_func(Login.account_login, key_name="token", username="jack", password="456")
    def get_project_id():
        token = cache.get("token")
        print(f"使用token:{token} 查询项目, 返回项目ID")
        return get_int(1, 1000)


    @staticmethod
    @dependent_func(get_project_id, key_name="pid")
    def get_module_id():
        pid = cache.get("pid")
        print(f"使用项目ID:{pid} 查询模块, 返回模块ID")
        return get_int(1, 1000)

在用例中直接调用 DepFunc.get_module_id 方法即可。

import seldom
from seldom.utils import cache, dependent_func
from common import DepFunc


class DependentTest(seldom.TestCase):


    @dependent_func(DepFunc.get_module_id, key_name="mid")
    def test_case(self):
        """
        sample test case
        """
        mid = cache.get("mid")
        print(f"模块ID: {mid}")


if __name__ == '__main__':
    seldom.main(debug=True)
    cache.clear()

2.测试用例也可以同时使用多个 @dependent_func() 装饰器依赖多个方法,顺序由上到下执行,这种方式主要用于被依赖的方法之间没有依赖关系。

# common.py
from seldom.testdata import get_int, username


class DataFunc:

    @staticmethod
    def get_name():
        return username(language="zh")

    @staticmethod
    def get_age():
        return get_int(1, 99)

在用例中使用多个@dependent_func()依赖装饰器。

import seldom
from seldom.utils import cache, dependent_func
from common import DataFunc


class DependentTest(seldom.TestCase):


    @dependent_func(DataFunc.get_name, key_name="name")
    @dependent_func(DataFunc.get_age, key_name="age")
    def test_case(self):
        """
        sample test case
        """
        name = cache.get("name")
        age = cache.get("age")
        print(f"名字: {name}, 年龄: {age}")


if __name__ == '__main__':
    seldom.main(debug=True)
    cache.clear()

参数化使用

参数化 @data()、 @file_data() 是seldom最重要的功能之一,能否和 @dependent_func() 一起使用? 当然可以。

import seldom
from seldom import data
from seldom.testdata import get_md5
from seldom.utils import cache, dependent_func


class DependentTest(seldom.TestCase):

    @staticmethod
    def user_login(username, password):
        """
        模拟用户登录,获取登录token
        """
        return get_md5(username+password)

    @data([
        ("case1", "foo"),
        ("case2", "bar"),
    ])
    @dependent_func(user_login, username="tom", password="t123")
    def test_case(self, _, keyword):
        """
        Used tuple test data
        """
        token = cache.get("user_login")
        print(keyword, "token", token)


if __name__ == '__main__':
    seldom.main(debug=True)
    cache.clear()

说明

1.@data() 装饰器必须写在 @dependent_func() 的上面。

2.运行两条用例,user_login() 被执行过一次后,第二次则不需要重复执行,直接返回结果。

 

总结:

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

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

软件测试面试文档

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

 

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

揭秘智慧礼品背后的故事

如若不是从事技术行业&#xff0c;在罗列礼品清单时&#xff0c;可能不会想到 “数据”&#xff0c;但幸运的是&#xff0c;我们想到了。如何将AI技术应用到当季一些最受青睐的产品中去&#xff0c;训练数据是这一智能技术的背后动力。很多电子设备或名称中带有“智能”一词的设…

TikTok赚钱攻略 | 这6个方法你必须知道

在浩瀚的网络世界中&#xff0c;TikTok成为了一个让普通人一夜成名的舞台。Khabane Lame和Charli DAmelio就是其中的明星例子。无论是Khabane简单的肢体幽默还是Charli的舞蹈视频&#xff0c;他们都凭借TikTok赚钱&#xff0c;并且成功转变了自己的人生轨迹。他们的故事证明&am…

【kafka】安装

也是第二次安装&#xff0c;蛮记录一下 1.安装kafka之前需要先完成zookeeper的安装 【zookeeper】安装 2. Apache Kafka官网下载 3. 解压完成后修改server.properties配置文件 修改日志文件存放路径 查看与zookeeper连接的端口是否和zookeeper服务所在的端口一致 &#xf…

BTI性能开销权衡及优化措施

BTI分支目标识别精讲与实践系列 思考 1、什么是代码重用攻击&#xff1f;什么是ROP攻击&#xff1f;区别与联系&#xff1f; 2、什么是JOP攻击&#xff1f;间接分支跳转指令&#xff1f; 3、JOP攻击的缓解技术&#xff1f;控制流完整性保护&#xff1f; 4、BTI下的JOP如何…

智能助手大比拼!5款热门思维导图软件细致评估!

思维导图是一种创造性的方法&#xff0c;集思广益&#xff0c;寻找不同想法之间的联系。如果你做得好&#xff0c;你可以为难题提出新的想法和解决方案&#xff0c;总结一篇文章或演示稿&#xff0c;让你的想法井然有序。在数字时代&#xff0c;纸质思维导图存在不能随意更改、…

Nginx内存池相关源码剖析(六)外部资源释放和内存池销毁

ngx_destroy_pool函数 先执行回调函数释放所有的外部资源&#xff0c;然后free释放所有的大块内存和小块内存。 // 释放外部资源&#xff0c;销毁内存池 void ngx_destroy_pool(ngx_pool_t *pool) {ngx_pool_t *p, *n;ngx_pool_large_t *l;ngx_pool_cleanup_t *…

[数据结构]——二叉树——堆排序

后续代码以此为基础 typedef int HPDataTyp; typedef struct Heap {HPDataTyp * a; int size; int capacity; } Hp; 1.首先我们需要掌握两种堆算法 1&#xff0c;堆向下调整算法 现在我们给出一个数组&#xff0c;逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整…

清明三天,用Python赚了4万?

每年4月&#xff0c;是Python圈子里接私活的旺季&#xff0c;特别是在节假日这种数据暴增的时间段&#xff0c;爬虫采集、逆向破解类的私活订单会集中爆发&#xff0c;量大价高。几乎所有的圈内人都在趁着旺季接私活。 正好&#xff0c;我昨天就做了一单爬虫逆向私活&#xff…

社科院与新加坡社科大学工商管理博士——结合顶尖学术力量,培养全球战略领导力

在当今全球化的时代&#xff0c;工商管理博士项目不仅仅是为了培养学术研究者&#xff0c;更是为了孕育出具有全球战略领导力的商业领袖。这样的项目需要顶尖的学术力量来引领&#xff0c;而中国社会科学院与新加坡社科大学正是这样的学术巨擘。两者联合培养的工商管理博士项目…

Python统计分析库之statsmodels使用详解

概要 Python statsmodels是一个强大的统计分析库,提供了丰富的统计模型和数据处理功能,可用于数据分析、预测建模等多个领域。本文将介绍statsmodels库的安装、特性、基本功能、高级功能、实际应用场景等方面。 安装 安装statsmodels库非常简单,可以使用pip命令进行安装:…

浅谈Java JVM

Java虚拟机&#xff08;Java Virtual Machine&#xff0c;简称JVM&#xff09;是Java语言的核心组成部分&#xff0c;它是一个抽象的计算机&#xff0c;负责执行Java字节码指令。JVM是Java平台无关性的基石&#xff0c;它为Java代码提供了一个标准的运行环境&#xff0c;使Java…

Java小白教学—五千字带你了解多线程机制及线程安全问题

基础概念 &#x1f4d6; 问题一 : 什么是线程&#xff1f;线程和程序、进程有什么区别&#xff1f; 程序&#xff1a;为实现某种功能&#xff0c;使用计算机语言编写的一系列指令的集合。 指的是静态的代码&#xff08;例如安装在电脑上的那些文件&#xff09; 进程&#xff…

UE5 编辑器启动模式下去掉左上角的Clink for Mouse Control

Edit > Editor Preferences > Game Gets Mouse Control 把这个勾去掉

【C++初阶】C++简单入门(长期维护)

本篇博客是对C的一些简单知识分享&#xff0c;有需要借鉴即可。 C简单入门目录 一、C前言1.C的概念&#xff1a;2.C发展历程3.C如何学&#xff1f; 二、C入门1.C关键字(C98标准)2.命名空间3.C输入&输出①概念说明②使用说明③特征说明④细节拓展⑤cout与cin的意义 4.缺省参…

freertos作业day1

1.总结keil5下载代码和编译代码需要注意的事项 1.&#xff09;仿真器设置&#xff1a; 点击魔术棒&#xff0c;选择debug选项&#xff0c;找到使用的仿真器&#xff0c;选择ST-LINK仿真器&#xff0c;点击setting&#xff0c;选择flash download ,勾选reset and run,选择pack…

竞技游戏新纪元:如何打造满足现代玩家需求的极致体验?

文章目录 一、现代玩家需求分析二、以玩家体验为核心的游戏设计三、个性化与定制化服务四、强化社交互动与社区建设五、持续更新与优化《游戏力&#xff1a;竞技游戏设计实战教程》亮点编辑推荐内容简介目录获取方式 随着科技的飞速发展和游戏产业的不断壮大&#xff0c;现代玩…

负荷预测 | Matlab基于TCN-GRU-Attention单变量时间序列多步预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于TCN-GRU-Attention单变量时间序列多步预测&#xff1b; 2.单变量时间序列数据集&#xff0c;采用前12个时刻预测未来96个时刻的数据&#xff1b; 3.excel数据方便替换&#xff0c;运行环境matlab2023及以…

DNF手游攻略:萌新入坑大全!

玩DNF手游国服已经正式定档&#xff0c;离上线已经越来越近了&#xff0c;很多小伙伴对于装备打造以及附魔还不是特别了解。如果你还不知道装备要怎么附魔&#xff0c;不要担心&#xff0c;本篇攻略将为你全面解析全职业过渡和毕业附魔推荐。 ​ 一、物理职业附魔推荐 1. 武器…

渗透测试信息收集

一、渗透信息收集流程 渗透测试过程前期&#xff0c;需要大量的完善的网站业务信息收集工作&#xff0c;大致信息收集流程为 1、网站域名信息探测 2、网站子域信息探测 3、网站敏感信息收集 4、网站安全工具核实 5、网站旁站利用情况 6、网站业务资产梳理 二、网站域名信息探…

【行为型模式】策略模式

一、策略模式概述 策略模式(又叫政策Policy模式)&#xff0c;属于对象行为模式下的&#xff1a;Strategy类提供了可插入式(Pluggable)算法的实现方案。 策略模式的定义-意图&#xff1a;定义一系列算法&#xff0c;将每一个算法封装起来&#xff0c;并让它们互相替换。策略模式…