基于pytest的服务端http请求的自动化测试框架?

1、引言

我有一个朋友是做 Python 自动化测试的。前几天他告诉我去参加一个大厂面试被刷了。

我问他是有没有总结被刷下来的原因。他说面试官问了一些 pytest 单元测试框架相关的知识,包括什么插件系统和用力筛选。但是他所在的公司用的技术是基于 unittest 的,没有用过 pytest。

我跟他说你可以和技术面试官说明,在实际过程当中你没有使用过 pytest,但是你可以后面再学。这哥们说:我就是这样跟面试官说的,但是面试官告诉我 pytest 现在已经是行业里面的主流,还在坚持用 unittest 说明我的技术已经过时了,没有跟上现在测试领域的发展。

实际上他在面试之前已经了解过 pytest 的一些基础用法,但是网上的一些资料,都是停留在用法和一些知识点的讲解,没有深入到 pytest 内部运行和一些高级特性。所以被问到的时候,自己临时抱佛脚的一些知识都没有用上。

后面我给这位朋友补习了一些关于 Python 的高级特性。现在我连同基础部分的内容一起贴出来,希望对 Python 自动化测试的一些朋友有所帮助。

2、为什么用单元测试框架?

首先我要说明一下什么是单元测试框架?

unittest 和 pytest 都是单元测试框架。单元测试指的是在编程过程当中形成的对函数或者是类下面的方法进行测试的一个过程。

在不使用任何框架的前提下,其实也是可以进行单元测试的。比如我们可以通过 if 判断
、异常处理或者是其他的流程控制来表示测试是否通过。

def add(a, b):return a + bdef test_add():ret = add(3, 4)if ret == 7:print("add 函数的测试通过")else:print("add 函数的测试失败")

如果要运行这个用例,需要手工调用 test_add 这个函数:

test_add()

接下来,使用 python 运行这个文件,就能得到测试结果:

python test_add.py

虽然说上面我们通过 if 判断,对一个函数进行了测试,而且得到了测试结果,但是流程是比较复杂的:

  • 首先我们需要人工去判断结果,
  • 第 2 我们需要通过 Python 去运行模块。
  • 第 3,我们还需要显性的去调用 test_add 这个函数。

这还只是在我们只测试了一个函数的情况下,当需要测试的函数或者类越来越多的时候,这个过程会越来越复杂。

而使用单元测试框架,可以极大的简化我们对单元测试的过程,使用单元测试框架以后,框架会帮我们自动去收集用例、运行用例、生成报告。


 

3、pytest 的基础使用

上面的测试代码使用 pytest 编写,可以这样写。

def add(a, b):return a + bdef test_add():assert 7 == add(3,4)

写完测试用例以后,我们只需要在目录下输入 pytest 指令,就可以自动运行用例,而且呢结果会直接显示在命令行的下方。

上面讲的是单元测试过程,也就是说对某个函数或者是类下面的方法进行测试,有的人可能会不理解。在实际工作过程当中很少进行单元测试啊,测试人员做的更多的是接口测试,UI 测试,pytest 怎么用呢?

实际上不管是接口测试还是 UI 测试,都是可以使用 pytest。当你进行接口测试的时候,你只需要把访问接口的过程封装成一个 Python 函数。

def visit_api():print("访问接口,得到结果...")return responsedef test_api():assert expected_response == visit_api()

当你进行 Web 测试的时候,你只需要操作浏览器的过程封装成一个函数?

def browser_method():print("点点点")return ui_responsedef test_web():assert expected_response == browser_method()

在这种情况下。接口访问和 Web 操作都是以函数形式存在的,我们直接去测试这个 Python 函数,也是一个单元测试的过程。

因为 pytest 是一个第三方的框架,所以我们先要安装。安装方式非常简单,只需要通过 pip 这个包管理工具安装就可以了。

pip install -U pytest

安装完成以后,我们可以向使用上面的那个例子一样:

  • 第 1 步:定义一个测试函数,这个测试函数通常会调用被测函数。
  • 第 2 步:使用 assert 断言,assert 后面可以跟任意的 Python 条件表达式。
assert 4 < 5assert "yuze" in "yuze wang"assert isinstance(6, int)

测试用例函数有 2 个注意事项:

  • 函数名称以 test_ 开头;
  • 保存测试用例的文件以 test_*.py 的形式或者 *_test.py 的形式。

例行用了以后呢,在命令行当中会显示 4 个部分的内容:

  • 第 1 个部分,测试用例和通过的结果,
  • 第 2 个部分,失败用例回溯信息,
  • 第 3 个部分,输出捕获信息,
  • 第 4 个部分,总结信息。

在拍 test 当中通过的测试用例,不会有特别详细的结果,但是这是失败的测试用例默认会有非常详细的结果,而且会帮你捕获错误原因。 

​现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:485187702【暗号:csdn11】

4、测试夹具(Fixture)是什么?

在测试过程当中,有时你需要提前给你的测试用例去准备一个运行环境。这个测试环境通常来说被称为测试夹具(Fixture),又被称为固定装置、测试固件等。

作者:小溪流
链接:https://www.zhihu.com/question/50182320/answer/2293584521
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

  • 当你要测试一个电器的时候,你需要提供不同的输入电压电流的环境,
  • 当你测试一台电脑网络的时候,必须要提供网络环境,
  • 当你要测试一个手机游戏能否被安装时,你需要提供一台手机环境,
  • 当你要测试一个软件能否登录的时候,你需要准备用户名和密码这样的用户环境,
  • 当你要测试一个数据库能否操作的时候,需要提供数据库的连接环境。

现在我们来举一个夹具的例子,我们需要测试一个注册的函数。这个注册函数提供两个参数,第 1 个参数是手机号,第 2 个参数是密码。注册函数的逻辑就是对手机号码和密码进行校验,如果通过校验表示注册成功,如果不通过表示注册失败。

def is_mobile(number: str):if re.search(r"^1[3-9][0-9]{9}$", number):return Truereturn Falsedef register(mobile, password):if is_mobile(mobile) and len(password) >= 6:return "success"return "fail"def test_register():assert "success" == register("13177778888", "123456")

这个测试用例并没有什么问题,但是它存在优化的空间。一个优化的空间是每个手机号码都是我们手工生成的,当需要编写多组数据测试时,会有一点费时间。现在我们可以编写一个函数,自动生成一个手机号码,当我有多组数据需要测试的时候,我只需要重复调用生成手机号码的函数,就可以获取测试数据。这个生成手机号码的函数呢,就是一个夹具。

def gen_a_mobile():"""随机生成 13 开头的手机号码。"""random_num = "".join([str(random.randint(1,9)) for i in range(9)])return "".join(["13", random_num])

pytest 提供了一种叫做依赖注入的机制,当一个函数被声明为夹具的时候,可以在测试函数中传入这个夹具的名称,pytest 会自动调用它。

import randomimport pytest@pytest.fixturedef gen_a_mobile():"""随机生成 13 开头的手机号码。"""random_num = "".join([str(random.randint(1,9)) for i in range(9)])return "".join(["13", random_num])def test_register(gen_a_mobile):assert "success" == register(gen_a_mobile, "123456")

pytest 当中的夹具系统非常非常的灵活,后面如果有时间的我专门写文章跟大家讲解夹具系统。

5、数据驱动和参数化

现在我们编写的函数和测试用例是 1 对 1 的关系,也就是说,当你想测试某个功能场景的时候,你必须要去编写一个对应的测试函数。当测试的场景越来越多,测试数据越来越复杂的情况下,需要编写更多的测心率函数,而这些函数的逻辑基本上是重复的。

 

在 pytest 当中可以使用参数化这种测试手段,简化编写用例函数的过程。我们并不需要为每一组测试数据单独去编写一个测试函数,而是采取多种数据共用一个函数的方式。如果测试操作几乎一致,可以重复使用这一个函数进行测试。

import pytestcases = [(1, 2, 3),("hello", "world", "hello world"),(1, "world", "1world")]@pytest.mark.parametrize("a,b,expected", cases)def test_add(a, b, expected):assert expected == add(a, b)

在这个例子当中,cases 这个变量存储了三组测试用例的数据,每一组测试数据用一个元组表示,元组的第 1 个元素代表 a,第 2 个元素代表 B,第 3 个元素代表预期结果。

@pytest.mark.parametrize("a,b,expected", cases) 这一行代码的意思是说,每一次从 cases 变量当中取出一组测试数据。分别用 a、b 、expected 三个变量接收,然后我们把这三个变量名作为函数的参数传递到 test_add 当中,就实现了参数化的过程。

当使用这一种参数化的手段进行测试的时候,测试数据和测试函数是多对一的关系,对于多组测试数据,我们只需要去编写一个测试函数,极大的提升了代码编写效率。

6、测试报告和插件

最后我们来说一下测试报告。pytest 当中的测试报告,通常是以插件的形式生成的,如果你想生成一个 HTML 格式的测试报告,可以先安装 pytest-html 这个插件。

pip install pytest-html

接下来你需要在运行用例的时候,在 pytest 命令后面加上 --html=<测试报告名称>.html

pytest --html=report.html

当运行完用例以后,你可以在当前目录下找到一个 report.html 的文件,打开就可以查看测试报告了。

pytest 之所以成为主流,有很多的原因,其中最重要的一个原因是因为其强大的插件系统。任何一个程序员,只要遵循一些简单的规范,就可以轻易的编写插件。后面我们再跟大家深入去研究 pytest 当中的夹具系统,插件系统和钩子函数这些特性。 

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 希望能帮助到你!【100%无套路免费领取】

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

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

相关文章

CUTLASS 1.3.3中的 Volta884_h884gemm

CUTLASS 是 CUDA C 模板抽象的集合&#xff0c;用于在 CUDA 内的所有级别和规模上实现高性能矩阵-矩阵乘法 (GEMM) 和相关计算。它采用了类似于 cuBLAS 和 cuDNN 中实现的分层分解和数据移动策略。 CUTLASS 最新版本为3.3&#xff0c;相比1.3.3变动较大。然而重温一下1.3.3仍然…

C++虚析构和纯虚析构解决delete堆区父类指针无法调用子类的构造函数

#include<iostream> #include<string>using namespace std;//虚析构和纯虚析构 class Animal { public:Animal(){cout<<"执行Animal的构造函数"<<endl;}~Animal(){cout<<"执行Animal的析构函数"<<endl;}virtual void …

【LeetCode二叉树进阶题目】606,102,107

二叉树进阶题目 606. 根据二叉树创建字符串解题思路及实现 102. 二叉树的层序遍历解题思路及实现 107. 二叉树的层序遍历 II解题思路及实现 606. 根据二叉树创建字符串 描述 给你二叉树的根节点 root &#xff0c;请你采用前序遍历的方式&#xff0c;将二叉树转化为一个由括号…

upload-labs关卡12(基于白名单的%00截断绕过)通关思路

文章目录 前言一、靶场需要了解的前置知识1、%00截断2、0x00截断3、00截断的使用条件1、php版本小于5.3.292、magic_quotes_gpc Off 二、靶场第十二关通关思路1、看源代码2、bp抓包%00截断3、验证文件是否上传成功 总结 前言 此文章只用于学习和反思巩固文件上传漏洞知识&…

千梦网创:创业一定要学会打造自己的榜样圈

一、状态 最近一直在学习刘克亚老师的书籍和课程。 克亚老师“国际自由族”的概念实际上就是实现“工作自由”。 财务自由只是一个奋斗目标&#xff0c;但“工作自由”是一种可实现的工作状态。 这种工作状态有一个特征就是全力打造一套能够无限趋近于“全自动”的赚钱系统。…

【喜报】云贝学员顺利通过OceanBase 数据库上机实验,OBCP证书到手了!!!

恭喜LIU同学历经2月&#xff0c;经过郭老师考前辅导顺利拿下OBCP证书&#xff01; 考试形式 OBCP V3.0考试分为笔试考试和实验考试两部分。 笔试考试&#xff1a; 考试形式:线下考点考试(官网预约) 考试时长: 90分钟 题目一共66道题&#xff08;从题库中随机抽取&#xff…

Git 教程

目录 Git 与 SVN 区别 Git 快速入门 学习目录 git简明指南 Git 安装配置 Git 工作流程、工作区、暂存区和版本库 Git 创建仓库 Git 基本操作 Git 分支管理 Git 查看提交历史 Git 标签 Git 远程仓库(Github) Git 服务器搭建 Git 是一个开源的分布式版本控…

【java】想要限制每次查询的结果集不能超过10000行,该如何实现?

文章目录 前言 前言 对于一些Saas化软件&#xff0c;当某个租户在执行查询SQL时&#xff0c;如果查询条件出现了BUG&#xff0c;导致去查了所有租户的数据&#xff0c;这种情况是非常严重的&#xff0c;此时就需要在架构层面做限制&#xff0c;禁止一些特殊SQL的执行&#xff…

C++电脑组装项目(涉及知识点:多态)

需求&#xff1a; #include <iostream> #include "Computer.h" #include "AbstractCpu.h" #include "AbstractMemory.h" #include "AbstractVideoCard.h" #include "IntelCpu.h" #include "IntelMemory.h" …

论文笔记:Localizing Cell Towers fromCrowdsourced Measurements

2015 1 Intro 1.1 motivation opensignal.com 、cellmapper.net 和 opencellid.org 都是提供天线&#xff08;antenna&#xff09;位置的网站 他们提供的天线位置相当准确&#xff0c;但至少在大多数情况下不完全正确这个目标难以实现的原因是蜂窝网络供应商没有义务提供有…

02 请求默认值

一、HTTP请求默认值&#xff1a;是用来管理所有请求共有的协议、网址、端口等信息的&#xff1b;通常情况下&#xff0c;一批量的接口测试&#xff0c;访问的是同一个站点&#xff0c;那么以上信息基本都是相同的&#xff0c;就不需要在每个请求中重复编写&#xff1b; 每个请…

【EI会议征稿】第九届能源科学与化学工程国际学术研讨会 (ISESCE 2024)

第九届能源科学与化学工程国际学术研讨会 &#xff08;ISESCE 2024&#xff09; 2024 9th International Symposium on Energy Science and Chemical Engineering 第九届能源科学与化学工程国际学术研讨会&#xff08;ISESCE 2024&#xff09;定于2024年3月22-24日在中国南京…