上篇博客中讲述了什么是接口测试,已经自动化接口测试流程,这篇博客总结如何实现接口自动化测试

(一)requests


requests库是Python对HTTP通信的一个工具,将http协议操作封装成简单的接口,能够让我们高效的编写各种网络自动化任务

安装requests库
我们可以通过pip命令来进行安装,在控制板中输入

后面的版本号可以不必一致,可以去官网查看

我们看上面successfully就是安装成功了
那我们也可以通过另一个命令来查看当前项目有什么库

接下来我们看如何使用这个库

首先就是获取一个http中的get请求到指定url

我们看一下这个方法的参数,url都不陌生就是我们要请求的网址,params就是我们的参数类似于我们在postman中这个位置填的数据
**kwargs是常见可选参数,就比如我们可以在里面设置请求头,cookie等

使用时只需要调用get接口

传入对应参数,就会给我们返回一个response对象,该对象包含了服务器给我们返回的一系列信息


当然之前我们学习请求形式不止get请求还有post,put等请求,我们也可以调用对应方法来进行url请求

我们再点进去看他们的源码

我们发现调用的都是request方法,所以我们想访问url时,也可以直接调用request方法,只不过需要我们手动去传入method用什么方式访问
我们这里举个实例,我们选择用一个博客详情的接口来举例

其实和我们使用postman类似
但在上面我们传递参数发现,可以使用params,json,data来传参
那么三者有什么区别?

parasms:使用params传参,参数是在url上体现的传递的是简单的键值对,常用于get请求来获取对应数据,因为可见所以她不适合传入敏感数据
data:使用data传参,参数在data中,常用于put或者post请求传递的是表单类型的数据,但是data是不支持嵌套的。键值对用 & 连接

json:使用json传参,参数在data中,常用于put或者post请求传递的是json的数据,json是支持嵌套的

上面就是request库的一些操作及使用, requests库主要是发送http请求,但是对于测试执行和管理就没怎么涉及到,接下来我们会使用pytest来完成测试的组织,执行,管理功能。


(二)pytest


我们这里选择使用pytest接口来实现自动化接口测试,除了pytest我们也可使用其他框架比如unnittest或者robot framework等

我们选择pytest是因为她的语法较为简单,且插件比较多,我们可以通过下载插件来完成各种功能

pytest的安装

我们安装pytest有个版本对应表,不同版本的pytest有最低适配的python版本

下载操作和刚刚我们下载requests操作类似,都是使用pip install操作来下载

同样我们可以使用pip list来看

安装好后,我们来看一下有没有pytest框架对于代码编写的区别
有pytest

没有pytest

我们发现如果没有pytest框架,我们要执行一个方法,需要一个main函数,并在函数中调用,若我们有了pytest框架,我们可以直接运行该方法,但是我们需要遵守pytest的命名规范,下面就来说一下怎样命名是可以被pytest识别到的

pytest框架默认命名格则

文件名:文件名需要以test_**来命名或者**_test来命名
测试类:测试类必须以Test开头,并且不能有__init__方法
测试方法:测试方法必须以test**开头


init和构造方法


注:测试类中不推荐有init方法(类似于java中的构造方法),但是我们可以定义
之所以不推荐是因为init方法是无法访问pytest fixtures的(执行顺序为:init方法->fixtures->其他方法)
而且构造函数只负责初始化并没有对应清理机制,且每次测试方法都会创建新的实例。

这一点要做一下区分,此时在pytest中的init方法和构造方法是有很大区别的
就比如我们局一个简单的例子,我们在python正常类中写一个init方法和一个类方法,之后我们实例化一个对象并多次调用类方法

我们发现只会调用一次构造函数,在多次调用方法时,也不会再调用构造函数,而当我们在pytest中创建init方法,我们再来看一下

他的输出是这样的

init方法在每次测试方法执行前都会重新调用一次(这是因为每个测试方法都是新的实例,测试之间不共享状态)

以上就是我们为什么不推荐使用init方法,为了处理init方法初始化的作用,pytest给我们提供了其他的初始化方法比如:setup/teardowm或者使用fixture  这些在之后我们也会再讲
注:上面在pytest中使用init方法仅限pytest 4之后的版本,在pytest 4之前版本,是禁止任何类有init方法的

pytest命令参数


pytest提供了很多命令行来控制测试的执行,以下是一些常用的命令航参数以及说明
pytest:在当前目录和其子目录下找到符合命名规范的类和方法并运行测试
pytest -v:增加输出的详细程序
pytest -s:显示测试中的print语句
pytest test_module.py :运行指定的测试模块
pytest test_dir:运行指定目录下的所有测试
还有一些其他的命令

我们在自己项目中使用pytest命令如下:
会自动执行符合pytest命名规则的方法

但是我们看显示框,发现信息很少,如果我们要显示更全面的信息,需要使用-v

但是上面并没有打印出111,这是因为如果我们想显示print语句,我们需要-s

当我们想指定测试方法执行时,我们需要手动指定,或者手动点击
手动指定


我们发现每次要执行指令时,我们要手动输入很长的一段命令,如何解决这个问题呢?

我们就需要把相关配置参数,统一放到pytest配置文件中

pytest配置文件


需要手动在当前项目下创建pytest.ini文件(文本文件),以下时一些常见的配置选项


在配置文件中我们可以这样指定

这样就是说明,我们默认在后面加上-vs,搜索的py文件为test_*,搜索的类为Test*
此时我们执行pytest,我们发现可以自动打印出原来pytest -vs才能执行出的表现

当我们更改搜索的py文件名称时我们来看看表现


但是同时.ini是不区分大小写的,如果我们想区分大小写,我们可以使用yml文件(之后会说)

前后置方法


上面我们说pytest里面不推荐有些版本甚至不能使用init初始化
那如果我们想执行测试用例前后执行一些额外操作,我们就需要用pytest提供的三种额外方法做前后置操作
setup_method和teardown_method:这两个方法用于类中每个测试方法的前置与后置操作
setup_class和teardowm_class:这两个方法用于整个测试类的前置和后置操作
fixture:使用fixture是比较推荐到方式,之后会详细说到fixture的使用

setup_method和teardown_method我们来举个例子

    def setup_method(self):print("setup method")def teardown_method(self):print("teardown method")def test_01(self):print("True example")def test_02(self):print("True example02")

就比如上述代码,我们使用setup_method和teardown_method


我们看现象,在测试方法前我们调用setup_method方法,在测试方法后调用teardown_method方法,每个测试方法都会进行一次调用

setup_class和teardown_class我们同样举个例子看现象

    def test_01(self):print("True example01")def test_02(self):print("True example02")def setup_class(self):print("setup method")def teardown_class(self):print("teardown method")


我们看到在一个类内,只会调用一次setup/teardown方法

断言


断言能够帮我们检测程序的状态是否符合我们的预期,如果断言失败,那么python解释器会给我们抛出一个AssertionError异常,pytest中允许我们使用python中的断言语句来验证预期和值

条件必须是一个布尔表达式,错误信息选填
这里简单写几个示例

class Test01():#断言整数a=1b=2assert a==b#断言字符串s1="str"assert s1=="str"#断言列表expectList=[1,'aaa',3.21]realList=[1,'aaa',3.21]assert expectList==realList#断言元组expectTuple=(1,'aaa',3.21)realTuple=(1,'aaa',3.21)assert expectTuple==realTuple#断言字典expectDict={'a':1,'b':2,'c':3}realDict={'a':1,'b':2,'c':3}assert expectDict==realDict#断言集合expectSet={'a','b','c'}realSet={'a','b','c'}assert expectSet==realSet

在执行后,我们看到报错信息还是非常的明显的,会告诉我们那个断言错误了


这样我们可以利用断言来判断接口的返回值是否符合我们的预期

def test1():url = "http://jsonplaceholder.typicode.com/posts/1"r = requests.get(url=url)expect_data = {"userId": 1,"id": 1,"title": "sunt aut facere repellat provident occaecati excepturi optio
reprehenderit","body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et
cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt
rem eveniet architecto"}print(r.json())assert r.json() == expect_dataassert r.json()['userId'] == 1

如果结果不符合预期就会断言失败

参数化


上述的代码,所有参数都是固定的,那么有没有一种方式可以像方法一样传参,让过程更加灵活可控呢?

我们可以用pytest内置的pytest.mark.parametrize来对测试函数的参数进行参数化
直接看代码

 @pytest.mark.parametrize("data",(1,2,3,4,5))def test_01(self,data):print("data: ",data)

  我们给方法设定一个参数data,然后通过pytest

  @pytest.mark.parametrize("data,result",[(3+5,8),(1+2,3)])def test_01(self,data,result):assert data==result

.mark.parametrize中第一个参数为要传的参数,第二个为参数的值

我们不止可以设定一个参数,也可以设置多个参数
代码如下:



此外除了可以在方法上使用这个参数化之外,在类上同样可以使用参数化

@pytest.mark.parametrize("data,result", [(3 + 5, 8), (1 + 2, 3)])
class Test01():def test_01(self, data, result):assert data == resultdef test_02(self, data, result):print(data,result)

现象如下,我们发现都会执行到

此时可能就会有疑问,当我们设定了同样的参数在类和方法上,会发生什么?可以来执行看下

@pytest.mark.parametrize("data,result", [(3 + 5, 8), (1 + 2, 3)])
class Test01():def test_01(self, data, result):assert data == result@pytest.mark.parametrize("data,result", [(1 + 5, 6), (2 + 2, 4)])def test_02(self, data, result):print(data,result)


上述告诉我们多次尝试对同一个参数进行重复参数化问题,解决办法也很简单
1.我们可以把类层和方法层参数合并到同一个层级
2.类层和方法层使用不同的参数名
除了可以手动指定参数外,我们也可以使用方法返回值来当作参数,只需要把手动指定参数的地方换成函数调用即可,类似于这样

注:当我们设定了参数化找不到对应参数时,是会报错的


fixture

用来提供测试函数所需要的资源或者上下文,有点类似于AOP面向切面编程的思想
以下是fixture的一些概念及使用场景
我们来看fixture的基础使用

class Test01():def fixture01(self):print("fixture1111")def test02(self):Test01.fixture01(self)print("test02")
class Test01():@pytest.fixture()def fixture01(self):print("fixture1111")def test02(self,fixture01):#    Test01.fixture01(self)print("test02")

我们看上述两个代码,第一种是在第二个方法中调用第一个方法
而第二种方法,是直接将函数名作为参数进行调用
我们看结果都是一样的

当然也可以在第一种的fixture方法上加上注解,也可以正常使用
那传到参数和方法中调用有什么区别呢?


除了基本使用fixture,也可以嵌套的使用fixture

class Test01():@pytest.fixture()def fixture01(self):return "01"@pytest.fixture()def est02(self,fixture01):#    Test01.fixture01(self)return fixture01def test03(self, est02):#    Test01.fixture01(self)print(est02)

与函数嵌套很类似

不止嵌套,我们同样可以在参数列表中调用多个fixture注解修饰的函数

class Test01():@pytest.fixture()def fixture01(self):return "01"@pytest.fixture()def est02(self,fixture01):#    Test01.fixture01(self)return "010203"def test03(self, fixture01,est02):#    Test01.fixture01(self)assert fixture01 in est02



fixture不止传参提供资源这一个用处,之前说过它可以用作于上下文
此时我们需要在代码中加上yield,这个主要是为了在我们运行测试时,确保它能够正确的自我清理,以便他不会干扰到其他的测试
我们使用yield而不是return,这样我们可以运行一些代码后,把对象返回给其他请求方法
但与return不同的是,该fixture的任何拆解代码要放在yield之后
一旦pytest确定了fixture,他会运行所有的fixture知道返回或者yield,然后执行下一个fixture重复此工作
测试完成后,pytest会逆向遍历fixture,对于每个yield后的fixture,运行yield语句之后的代码

class Test01():@pytest.fixture()def fixture01(self):print("start")yieldprint("stop")def test03(self, fixture01):#    Test01.fixture01(self)print("test03")

我们预期的表现是先打印对应方法中调用的fixture在yield前的代码,然后执行函数体,最后执行yield后的代码,看现象

带参数的fixture
看下这个注解的源码,我们看到有很多参数,但是我们上面在使用时,暂时没涉及到,这里来讲一下参数都有什么用


scope:
function:每个测试函数会调用fixture(也是默认的值)
class:在同一个测试类中共享这个fixture

class Test01():@pytest.fixture(scope="class")def fixture01(self):print("start")yieldprint("stop")def test05(self):#    Test01.fixture01(self)print("test03")def test03(self, fixture01):#    Test01.fixture01(self)print("test03")def test04(self):#    Test01.fixture01(self)print("test04")

按顺序先执行test05方法,因不涉及到fixture方法所以还没有调用,到了test03,先执行fixture方法中yield前的部分,等到class结束后执行yield后的部分
module:在一个文件里共享这个fixture
session:整个测试会话中共享这个fixture

autouse:默认参数为false,代表我们需要显示传入,才会调用,如果设置为true,就代表每个测试函数都会自动的调用fixture
params:用于参数化,fixture支持列表,每个参数都会让fixture执行一次,类似for循环
ids:与params搭配使用,为每个参数化实例指定标识符
类似这样

@pytest.fixture(params=[1, 2, 3],ids=["测试值1", "测试值2", "测试值3"]
)
def number(request):return request.param

name:用来给fixture方法设定一个名称,如果使用name,则在测试函数中需要使用这个名称来引用fixture


剩下的命令,下一篇再说

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

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

相关文章

信息安全及防火墙总结

1.1 信息安全现状及挑战信息安全概述 信息安全:防止任何对数据进行未授权访问的措施,或者防止造成信息有意无意泄漏、破坏、 丢失等问题的发生,让数据处于远离危险、免于威胁的状态或特性。 网络安全:计算机网络环境下的信息安全。…

20250808组题总结

A - A Pak Chanek 有一个包含 nnn 个正整数的数组aaa。由于他正在学习如何计算两个数字的向下取整平均值,他希望在他的数组 aaa 上进行练习。当数组 aaa 至少有两个元素时,Pak Chanek 将执行以下三步操作: ∙\bullet∙选择两个不同的索引 ii…

【Python 语法糖小火锅 · 第 5 涮 · 完结】

一、糖味一句话 Python 3.10 的 match-case 把「类型 值 嵌套」一次性拆开, 可读性 10,bug 数 10,if-elif 可以安心退休了。二、1 行示例 3 连发 # ① 值匹配 match status:case 200: msg "ok"case 404: msg "not found&q…

写 SPSS文件系统

写入 SPSS 系统文件(.sav、.zsav) 以下为相关的 SPSS 命令(以大写形式 CAPS 呈现) savFileName : str SPSS 数据文件的文件名 以 .sav 结尾的文件使用旧版压缩方案压缩。 以 _uncompressed.sav 结尾的文件不压缩,这在需…

云服务器--阿里云OSS(1)【阿里云OSS简单介绍以及环境准备】

一、阿里云OSS简介 定义:阿里云OSS(Object Storage Service)是阿里云提供的对象存储服务,支持海量数据的存储和管理。 存储方式:基于“对象存储”,文件以对象形式存储,无需管理文件系统结构。 …

R语言代码加密(1)

1、使用Compiler包library(compiler) cmpfile("1.R")#实现对R脚本的整体加密 compiler::loadcmp("1.Rc")#调用R脚本存在问题是,该方法仅对脚本进行加密。在加载生成的Rc文件后,脚本内具体函数,是可以看到具体内容的。针对…

【面试场景题】通过LinkedHashMap来实现LRU与LFU

文章目录一、LRU与LFU的概念1. LRU(Least Recently Used,最近最少使用)2. LFU(Least Frequently Used,最不经常使用)二、LinkedHashMap的特性三、用LinkedHashMap实现LRU实现代码:原理说明&…

第5章 Excel公式与函数应用指南(2):数学函数

5.2 数学函数 Excel作为强大的数据处理工具,其内置的数学函数体系为用户提供了丰富的计算能力。从基础的四则运算到复杂的指数对数计算,从简单的数值舍入到专业的矩阵运算,Excel的数学函数几乎可以满足各类计算需求。 本节将重点为您解析七个常用且实用的数学函数:求和函…

mysql复制连接下的所有表+一次性拷贝到自己的库

1.导出链接下的所有数据mysqldump -h 地址 -u 数据库名 -p --all-databases --single-transaction --master-data2 > all_dbs.sql2.导入自己的库mysql -h 127.0.0.1 -u root -p < all_dbs.sql3.指定导出某些库mysqldump -u root -p --databases db1 db2 db3 > /path/t…

开发手札:UnrealEngine和Unity3d坐标系问题

最近把一套网络模块和一套组件模块从u3d改造到ue4。网络模块通用性很高&#xff0c;毕竟协议都是通用网络协议&#xff0c;改造后没啥问题。但是改造组件模块的时候就遇到了问题。首先&#xff0c;unity3d的坐标系是标准左手坐标系&#xff0c;如下&#xff1a;同时自己的几何算…

QML 鼠标穿透

事件&#xff1a; 有一个输入框(TextField)&#xff0c;需要实现鼠标悬浮时改变边框颜色&#xff0c;鼠标移出后恢复原来边框颜色&#xff1b; 这时如果需要实现此功能&#xff0c;就得使用到MouseArea&#xff0c;鼠标操作区域填充满整个TextField。 然后实现鼠标移入移入出的…

VR 设备 PCB 怎样凭借高频材料达成高速传输

VR 设备的沉浸式体验依赖于高分辨率图像与低延迟交互&#xff0c;这要求设备内部数据传输速率达到 10Gbps 以上&#xff0c;而印制线路板&#xff08;PCB&#xff09;作为信号传输的核心载体&#xff0c;其材料性能直接决定传输效率。高频材料凭借低介电常数&#xff08;Dk&…

Oracle字段操作

1. 新增字段 -- 新增字段 ALTER TABLE MES.WT_SUPPLEMENT_RECORD ADD (PAR_ATTR3 NUMBER DEFAULT NULL);2. 修改字段类型 -- 修改字段类型 ALTER TABLE MES.WT_SUPPLEMENT_RECORD MODIFY (PAR_ATTR3 VARCHAR2(32));3. 删除字段 -- 删除字段 ALTER TABLE MES.WT_SUPPLEMENT_RECO…

【原创】基于 Flask 的简单文件收集器

在单位内网环境中&#xff0c;我经常需要收集 pdf 格式的记录表。于是我基于 ai ide&#xff0c;开发了一个基于 Flask 开发的轻量级文件上传服务项目&#xff0c;部署在单位飞腾芯的银河麒麟系统上&#xff08;当然由于 python 的跨平台&#xff0c;在 windows 和 mac 上也可部…

学习Java的Day28

今天在昨天完成的留言板项目基础上&#xff0c;我进一步开发了一个酒店房型管理系统。该系统采用MVC架构&#xff0c;主要功能是对酒店房型信息进行增删改查操作。数据库设计方面&#xff0c;我创建了hotel_room_type表&#xff0c;包含以下字段&#xff1a;id&#xff1a;主键…

Leetcode——556. 下一个更大元素 III

题目链接&#xff1a;556. 下一个更大元素 III &#xff08;由于图片上传失败&#xff0c;不贴原题目了&#xff0c;有需要可以前往力扣查看&#xff09; 本文给出该题的单调栈做法&#xff0c;同时绕过所有库函数&#xff0c;所有逻辑均自行实现。 本题的思路就是从右向左按…

Idea打包可执行jar,MANIFEST.MF文件没有Main-Class属性:找不到或无法加载主类

背景&#xff1a;IDEA传统方法【Project structure】-->artifact---->build的模式&#xff0c;打包【Maven】项目&#xff0c;发现生成的可执行jar包&#xff0c;显示【找不到或无法加载主类】。但是用【Maven】的Assembly可以正常生成。期望用传统方法实现打jar包方法&a…

检索增强生成:RAG(Retrieval Augmented Generation)

什么是 RAG&#xff1f;为什么使用 RAG&#xff1f;LLM 微调 和 RAG&#xff1f;实战什么是 RAG&#xff1f; RAG 在论文《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》中被引入&#xff0c;原论文是这样描述的&#xff1a; 探索了一种 通用的 检索增…

Android 设置/修改系统NTP服务地址

Android 手机的 NTP 时间同步&#xff08;网络时间同步&#xff09;主要依赖网络&#xff0c;但系统时间来源还包括其他方式&#xff0c;整体时间校准机制是多种来源的结合。具体可分为以下几类&#xff1a; 1. 网络 NTP 同步&#xff08;最主要方式&#xff09; 这是 Androi…

Ubuntu22.04 安装vitis2023.2 卡在“Generating installed device list“.

关于这个问题&#xff0c;xilinx有官方说明&#xff0c;链接 原因&#xff1a;问题是 Ubuntu 20.04 缺少 libtinfo.so.5 库。 解决办法&#xff1a; sudo apt-get install libtinfo5