服务端测试知识汇总

news/2024/5/7 21:47:25/文章来源:https://blog.csdn.net/suruoxun/article/details/128137072

目录

服务端测试思想

经济学⻆度

⾦字塔模型

技术⻆度

HTTP协议 

三次握⼿ 

HTTP完整请求 

通信模式 

URI信息

请求⽅法 

请求状态码 

请求/响应头

常⽤请求数据格式 

COOKIE请求流程 

 SESSION请求流程

TOKEN请求流程 

API测试维度 

单接⼝测试

多个接⼝测试

开放平台API

Requests实战

Requests概述

GET⽅法实战

POST⽅法实战

SESSION处理

 token实战

Requests封装

轻量级测试框架-Tavern框架

Tavern基本使⽤

MockServer

moco 

mock


服务端测试思想

经济学⻆度

在软件测试中,⼀般性的我们建议测试越早投⼊进去,最后它的成本⽐较低,这是因为越早期的投⼊进去进⾏整个测试,能够发现底层架构的设计是否合理,以及能够尽早的发现问题,从⽽更快的解决问题,这样修复问题它的成本⽐较低。如发现的问题可能需要颠覆⽬前的架构设计和MQ中间件的交互,那么这个时候,这个问题在早期发现的时候,修复它的成本是很低的,如果到后⾯产品集成到⼀起发现了该问题,修复它的成本是⾮常⾼的。

⾦字塔模型

⾦字塔的模型是软件测试⾥⾯最具有指导思想的模型之⼀,在这个模型⾥⾯,它通过更加直观的⽅式把软件测试从宏观的思维分为三层,最底层的是单元测试,中间层是API测试,最上层是UI⾃动化测试,如下所示:

在⾦字塔的模型中,在测试分为三个维度来进⾏思考,分别是单元,服务和UI三个层级。这地⽅主要的说下 服务层的测试,在服务层的测试维度中,主要针对的是业务接⼝的测试,来验证接⼝功能是否完整,如内部逻辑, 异常处理。这样的⽬的是验证接⼝它是否稳定,所以接⼝的测试相对⽽⾔⽐较容易⽽且更加⾼效,测试⽤例的维护成 本也低。有很多主流的测试⼯具都可以做接⼝测试,如PostMan,JMeter,SoupUi等,除了⼯具还有在Python语⾔中 很多的第三⽅的库都是可以来做接⼝测试的,如:urllib,requests,aiohttp等。在新的基于微服务的架构模型中,我们会针对⾦字塔的测试模型做⼀个微型的调整,具体调整为如下:  

在如上这个测试模型中,在⾦字塔的底部从下往上移动,应该投⼊的测试越来越少,这也符合软件测试经济学的成本思想。应该更多精⼒的投⼊更多底层的测试。底层的测试将主要就包含了在微服务的架构模型中,针对单个服务的测试,多个服务多实例的测试,以及服务与服务之间的调⽤和测试,以及服务之间的数据⼀致性,和服务 与MQ中间件之间的交互,以及服务与DB层⾯的交互。 

技术⻆度

  •  企业从传统架构往saas,paas化架构转型
  • ⼤数据技术的全⾯落地,那么就演变⽽来的是⼤数据平台中资源调度,资源管理,资源优先级,资源合理化的使⽤
  • 技术的复杂性,产品的技术架构呈现混沌形态
  • 如何在不确定性的技术架构下经济形态下保持业务的⾼速发展

HTTP协议 

在ISO的模型中(7层⽹络协议分别是:物理层,数据链路层,⽹络层,传输层,会话层,表示层,应⽤层)上下层之间进⾏交互时需要互相遵守的约定叫“接⼝”,同⼀层之间的交互所遵守的约定叫“协议”。所谓协议就是客户端与服务端交互的语⾔是⼀致的,下⾯演示交互不⼀致的情况,具体如下:

 协议⼀致的时候,沟通是没有任何的障碍的,如下所示:

三次握⼿ 

当然在这个过程中,我们还需要关注三次握⼿之间的⽹络交互,它的具体信息为Client端发送连接请求报⽂,Server端接受连接后回复ACK报⽂,并为这次连接分配资源。Client端接收到ACK报⽂后也向Server段发送ACK报⽂,并分配资源,这样TCP连接就建⽴了。总结三次握⼿具体为:

  • 第⼀次握⼿:起初两端都处于CLOSED关闭状态,Client将标志位SYN置为1,随机产⽣⼀个值seq=x,并将该数据包发送给Server,Client进⼊SYN-SENT状态,等待Server确认;
  • 第⼆次握⼿:Server收到数据包后由标志位SYN=1得知Client请求建⽴连接,Server将标志位SYN和ACK都置为1,ack=x+1,随机产⽣⼀个值seq=y,并将该数据包发送给Client以确认连接请求,Server进⼊SYN-RCVD状态,此时操作系统为该TCP连接分配TCP缓存和变量;
  • 第三次握⼿:Client收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=y+1,并且此时操作系统为该TCP连接分配TCP缓存和变量,并将该数据包发送给Server,Server检查ack是否为y+1,ACK是否为1,如果正确则连接建⽴成功,Client和Server进⼊ESTABLISHED状态,完成三次握⼿,随后Client和Server就可以开始传输数据。 

                

HTTP完整请求 

 HTTP是应⽤层的协议,它不需要刻意的去关注底层⽹络传输层协议的东⻄。在整体应⽤层的协议中,通俗的说在整个API的测试维度上,需要关注的是⼀个完整的HTTP请求流程,请求⽅法,请求头响应头,COOKIE请求流程,SESSION的请求流程和TOKEN的请求流程,以及HTTPS的请求流程。在微服务的架构模式下,使⽤的也是轻量级的通信模式(REST API),在微服务的架构模式中,需要清楚的是它的通信可以分为同步通信模式和异步通信模式,或者更加具体本质的说就是请求/响应和异步请求/响应(发布/订阅模式)。在API的⾃动化测试中,我们更多关注的是HTTP应⽤层的交互,因为即使主流的架构如微服务架构,它的通信模式也是基于REST API轻量级的通信模式。在HTTP的协议中,⼀个完整的HTTP请求流程具体为:

  • 客户端与服务端之间建⽴TCP的连接请求
  • 客户端向服务端发送Request的请求
  • 服务端Response相应回复给客户端
  • 客户端与服务端之间关闭TCP的连接请求

更多关于http请求可以关注 : HTTP协议_菜鸟学识的博客-CSDN博客

通信模式 

同步通信

在客户端与服务端在进⾏交互的时候,通信模式主要分为同步通信和异步通信。同步通信简单的可以理解为客户端发送请求给服务端,服务端必须得回应客户端的请求。所以同步通信它存在如下的缺点,具体为:

  • 容易超时,客户端发送请求后,服务端迟迟没有回应客户端的请求
  • 如果请求是存在⼤的计算量和逻辑存在问题,就会导致请求堵塞,后⾯的都积压

异步通信

由于同步交互存在超时以及堵塞的情况,所以也就有了异步的交互。在异步的交互中,客户端和服务端互相不需要关注对⽅的存在,只需要关注对应的MQ的消息,客户端与服务端的交互主要是会通过MQ的消息中间件作为消息的传递来进⾏交互

URI信息

URI是英⽂单词Uniform Resource Identifier的简写,主要是⽤来识别被⽤于互联⽹主⻚地址(邮箱地址)等。URL的英⽂单词是Uniform Resource Locator,URL主要⽤来表示互联⽹中资源的具体地址。URL与URI中,URL是⼀个狭义的概念,⽽URI它更加具备深度和⼴度,⽐如URI可以⽤于除WWW之外的其他应⽤层协议中。针对该地址,可以分解为如下的信息:

  • Https://:表示的是应⽤层的协议
  • Item.jd.com:服务器域名地址信息
  • 12516591.html:具体的资源地址信息

请求⽅法 

在HTTP的应⽤层协议中,常⽤的请求⽅法具体为GET,POST,PUT,DELETE的请求⽅法,具体如下所示:

请求状态码 

当客户端向服务端发送⼀个请求后,服务端响应回复返回给客户端,在返回的信息中会包含⼀个HTTP请求头的状态码信息⽤以响应客户端的请求。在⽹站https://http.cat中可以看⻅各个不同表情的状态码的显示,如调⽤https://http.cat/504就会显示如下对应的信息。常⽤的状态码具体为:

  • 200 请求成功
  • 301 永久重定向
  • 302 临时重定项
  • 400 Bad Request 客户端请求错误
  • 401 Unauthorized
  • 403 Forbidden
  • 404 请求的资源不存在
  • 405 不被允许的请求⽅法
  • 500 服务器内部错误
  • 504 GateWay Timeout

请求/响应头

常⽤请求数据格式 

COOKIE请求流程 

 HTTP状态是⽆状态的协议,所以也就导致了COOKIE技术的发展,早期的产品基本对于产品认证体系使⽤的都是COOKIE的技术,COOKIE它是存储在客户端,在安全⻆度上不怎么友好

cookie是存储在客户端记录客户信息的一小段文本,由服务器生成发送给浏览器,下一次请求时会把该cookie发送给服务器(组成:key value,有效域,失效时间,安全标志(https))

 SESSION请求流程

session是存储在服务器上,客户第一次发送请求,服务器生成一个sessionId,并返回给客户端通过cookie,客户端再次发送请求给服务器的时候带着cookie(有sessionId),服务器就知道发请求的是谁了

 具体我们以⼀个登录为案例,login的请求⽅法是登录,index是访问主⻚,具体如下:

TOKEN请求流程 

token是产生的过程也是服务端返回一个带签名的token,存储在客户端,再次请求的时候header里带上token,服务器以同样的算法对数据进行计算比较,和session相比,以token的形式,服务端不用存储sessionId了

API测试维度 

单接⼝测试

接⼝维度总结如下⼏点:

  • 验证必填参数是否为空
  • 验证参数的数据类型是否做了校验
  • 验证参数的字段⻓度是否做了校验
  • 接⼝的安全性校验和性能校验

对单个API的测试,如果测试的API涉及到⽀付以及与⾦钱有关系的接⼝,都需要考虑API的安全测试,可以从下⾯⼏个维度来思考,分别是: 

是否增加了反爬⾍的机制
是否增加了请求次数的限制
是否增加了对应的请求头信息
是否增加了鉴权的认证信息(基本认证,常规认证,⾃定义认证)
是否对请求进⾏了加密
是否在被请求的服务端增加了IP的限制(⽩名单设置和IP的限制请求)

API的性能测试主要是基于服务的测试,可以使⽤常规的测试⼯具如JMeter测试⼯具来进⾏这部分的测试。 

多个接⼝测试

单个接⼝测试是必要的,但是⽆法保障到全链路的产品质量保障,所以需要基于产品全链路的质量保障,也就是业务场景的测试,简单的说就是通过API的测试技术,模拟⼈的操作⾏为,实现产品业务场景的覆盖,这种覆盖包含了产品正常的业务逻辑以及异常的程序逻辑判断。在基于业务场景的测试中,需要考虑的是参数上下关联的解决⽅案和思路,如有⼀个图书管理系统,可以增加书籍,查看增加书籍的信息,修改书籍的信息以及删除数据的信息,那么在链路的测试场景设计中,需要考虑的是添加书籍信息成功后,需要拿到书籍的ID,这样在后⾯的业务测试中才能够对添加的书籍信息进⾏信息的查询,信息的修改和信息的删除。这地⽅就会涉及使⽤到函数的返回值,把添
加书籍成功后书籍ID通过函数返回值返回后,在下个请求中调⽤这个变量。如编写⼀个函数返回值的代码具体如下:

def login(username,password):if username=='wuya' and password=='admin':return 'dfhj378dfghjw6dfh'else:return Falsedef profile(token):if token=='dfhj378dfghjw6dfh':print('欢迎您购买《Python⾃动化测试实战》视频课程')else:return '请先登录系统,谢谢!'if __name__ == '__main__':profile(login('wuya','admin'))

开放平台API

在实际的⼯作场景中,经常涉及到对应和第三⽅公司的对接,或者说公司提供给第三⽅公司的API,这样的API我们称呼为开放平台,也就是open api。针对开放平台,本质上我们可以理解为“赋能”。open api都是有加密的⽅式的,⼀般业界都是有统⼀的标准来进⾏加密,以及进⾏很难破解的过程。

Requests实战

Requests概述

Requests在官⽅的⽂档中,有这么介绍的⼀句话,具体为:HTTP For Humans,翻译过来就是:“让HTTP服务⼈类”。Requests是⾮常优秀的⼀个Python的第三⽅库,它在HTTP的应⽤层的协议中,客户s端与服务端的交互请求⾮常的轻量级,交互⾮常的友好。下⾯还是通过具体的案例代码来演示下Requests的基本使⽤⽅法。

GET⽅法实战

在处理GET请求⽅法的时候,我们通常需要处理url中的请求参数,如
https://www.xx.com/name=wuya&age=18,下⾯具体演示下这部分的应⽤,案例代码如下:

import requests,json
def getMethod():r=requests.get(url='http://httpbin.org/get')print(json.dumps(r.json(),ensure_ascii=False,indent=True))

再次来看params的请求参数的应⽤,具体如下:

import requests,json
def getMethod():params={'name':'wuya','age':18}r=requests.get(url='http://httpbin.org/get',params=params)print(r.url)if __name__ == '__main__':getMethod()

特别注意:不管是那个请求⽅法,凡事路径的参数,我们都是可以使⽤params的参数来进⾏解决的。

POST⽅法实战

在POST的请求⽅法中,它的形式参数存在两种,⼀种是json,还有⼀个是data,具体源码为:

def post(url, data=None, json=None, **kwargs):r"""Sends a POST request.:param url: URL for the new :class:`Request` object.:param data: (optional) Dictionary, list of tuples, bytes, or file-likeobject to send in the body of the :class:`Request`.:param json: (optional) json data to send in the body of the :class:`Request`.

⼀般性的,请求数据格式为application/json中,如果使⽤json的参数,数据是字典的数据类型,如果参数是data,数据类型是字符串的类型。针对登录的微服务来进⾏测试,具体测试代码如下:

import requests,json
dict1={"password":"admin","sex":"男","age":18
}
def jsonRequest():'''请求参数为json'''r=requests.post(url='http://localhost:5000/login',data=json.dumps(dict1),headers={'content-type':'application/json'})print(r.json())
def dataRequest():'''请求参数为data'''r=requests.post(url='http://localhost:5000/login',data=dict1,headers={'content-type':'application/json'})print(r.json())def dataStrRequest():'''请求参数为data,但是进⾏了序列化的处理'''r=requests.post(url='http://localhost:5000/login',data=json.dumps(dict1),headers={'content-type':'application/json'})print(r.json())if __name__ == '__main__':while True:f=int(input('1、json 2、data 3、dataStr\n'))if f==1:jsonRequest()elif f==2:dataRequest()elif f==3:dataStrRequest()else:break

 执⾏结果信息如下:

1、json 2、data 3、dataStr
1
{'message': {'username': '⽤户名不能为空'}}
1、json 2、data 3、dataStr
2
{'message': 'Failed to decode JSON object: Expecting value: line 1 column 1 (char 0)'}
1、json 2、data 3、dataStr
3
{'message': {'username': '⽤户名不能为空'}}
1、json 2、data 3、dataStr
4

SESSION处理

我们就以登录为案例,把登录成功后的token信息返回,然后再下次请求的时候带上它登录成功后的登录信息。

import requestsdef login():r = requests.post(url='https://home.51cto.com/index?reback=https%3A%2F%2Fedu.51cto.com%2Fcenter%2Fuser%2Findex%2Flogin-success%3Fsign%3Da0c8BVMJUQNUBwQIVFFTAlABAQBQCAEGUFVRU1ZQTBVASwgaTFwFRkoCBVsQXR9QW10eAQReQwEUTQJZFkpLBB9UV1YXTBNWFhhXVxFAQlZVAFJa&iframe=0&is_go_to_user_set_mobile=1',headers={"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36","Content-Type": "application/x-www-form-urlencoded","Referer": "https://home.51cto.com/index?reback=https://edu.51cto.com/center/user/index/login-success?sign=a0c8BVMJUQNUBwQIVFFTAlABAQBQCAEGUFVRU1ZQTBVASwgaTFwFRkoCBVsQXR9QW10eAQReQwEUTQJZFkpLBB9UV1YXTBNWFhhXVxFAQlZVAFJa&relogin=1","Cookie": "_ssxmod_itna2=QqjxBDyDgG5eq4BPGKHnrIKPhxGr27bo4iKG8D8d6WeGXub4GaiQQIkvCr0Ix8gno5uYB2hqHVCW35+OtKAebtPirQPvqLtQm6Kn1d2ZwFHHzGSnuWcratOFCYTTNBfRb92Vu0zQT6PiexBNYnWOiaRWTQvOtBhH=rYF2151epK1EEoFO4PxAgK4ED07KDrbiFqaqQrTA9wdY2STUtE5qD08DYI54D==; acw_tc=2760779416489697187698597ef95319033b93239ae9f5b89268f81cb55c6c; _ourplusReturnCount=3; _ourplusReturnTime=122-4-3-15-8-39; login_from=edu.51cto.com; reg_from=edu.51cto.com; Hm_lpvt_844390da7774b6a92b34d40f8e16f5ac=1648969720"},data={"_csrf": "dzRpQVd3emUHcjgGPARDVgViRCUcMRzPTA5X1wnAwFNEg==","LoginForm[username]": "13222245195","LoginForm[password]": "123","show_qr": "0"})return r.cookies#print(r.status_code)
#print(r.cookies)
#print(r.text)def profile():r = requests.get(url='https://edu.51cto.com/center/course/lecturer/course',cookies=login())print(r.status_code)print(r.text)profile()

 token实战

import requestsdef login():r = requests.post(url='http://23.95.142.233:8000/login/auth/',json={"username": "1322245195", "password": "168888"})return r.json()['token']def index():r = requests.get(url='http://23.95.142.233:8000/interface/index',headers={'Authorization': 'JWT {0}'.format(login())})print(r.status_code)print(r.text)

Requests封装

import requestsclass Requests:def request(self,url,method='get',**kwargs):if method=='get':return requests.request(url=url,method=method,**kwargs)elif method=='post':return requests.request(url=url,method=method,**kwargs)elif method=='put':return requests.request(url=url,method='put',**kwargs)elif method=='delete':return requests.request(url=url,method='delete',**kwargs)def get(self,url,**kwargs):return self.request(url=url,**kwargs)def post(self,url,**kwargs):return self.request(url=url,method='post',**kwargs)def put(self,url,**kwargs):return self.request(url=url,method='put',**kwargs)def delete(self,url,**kwargs):return self.request(url=url,method='delete',**kwargs)

轻量级测试框架-Tavern框架

Tavern基本使⽤

Tavern是⼀款轻量级的测试框架,集合Pytest的测试框架,可以把测试的描述信息(API的请求信息)以及测试断⾔都可以编写在Yaml的⽂件中,然后结合Pytest的测试框架直接解析Yaml就可以来批量的执⾏。在Tavern的测试框架中,它追求的是“Easier API testing”的设计理念,不过从⽬前实践的应⽤来看,它是符合这样的⼀种简单的模式的,Easy to Write, Easy to Read and Understand。下⾯我们⾸先来安装它,安装的命令为:

pip3 install tavern==1.12.2

下⾯我们把之前编写的登录服务的测试⽤例,整合到Yaml的⽂件中,Yaml⽂件的名称为:test_login.tavern.yaml,具体Yaml⽂件的内容为:

test_name: 登录微服务GET请求stages:- name: 登录微服务GET请求request:url: http://127.0.0.1:5000/loginmethod: GETresponse:status_code: 200json:status: 0msg: okdata: this is a login page---
test_name: 用户名信息为空stages:- name: 用户名信息为空request:url: http://127.0.0.1:5000/loginmethod: POSTdata:password: adminage: 18sex: 男response:status_code: 400json:message:username: 用户名不能为空---
test_name: 密码信息不能为空stages:- name: 密码信息不能为空request:url: http://127.0.0.1:5000/loginmethod: POSTdata:username: adminage: 18sex: 男response:status_code: 400json:message:password: 账户密码不能为空---
test_name: 年龄不能为正整数stages:- name: 年龄不能为正整数request:url: http://127.0.0.1:5000/loginmethod: POSTdata:username: adminpassword: adminage: asdsex: 男response:status_code: 400json:message:age: 年龄必须为正正数---
test_name: 验证性别只能是男或者女stages:- name: 验证性别只能是男或者女request:url: http://127.0.0.1:5000/loginmethod: POSTdata:username: adminpassword: adminage: 18sex: asdresponse:status_code: 400json:message:sex: 性别只能是男或者女---
test_name: 验证性别只能是男或者女stages:- name: 验证性别只能是男或者女request:url: http://127.0.0.1:5000/loginmethod: POSTdata:username: adminpassword: adminage: 18sex: 男response:status_code: 200json:username: adminpassword: adminage: 18sex: 男

 执⾏的命令具体为:

python3 -m pytest -v -s test_login.tavern.yaml

MockServer

被测系统在运⾏时候会时常依赖另外⼀些系统,依赖会导致测试的复杂化,并减慢测试速度,基于这样的现实考虑,就需要⼀种单独测试被测系统的⽅法,解决⽅案是测试替身(Test double)来消除被测系统的依赖性,测试替身是⼀个测试对象,该对象负责模拟依赖项的⾏为。什么是mock?mock简单的理解就是开发在开发的过程中,需要依赖⼀部分的接⼝,但是对⽅没有提供或者环境等等情况,总之是没有,那么开发使⽤mock server⾃⼰来mock数据,⽅便⾃⼰正常的进⾏开发和对编写的功能进⾏⾃测。

moco 

在https://github.com/dreamhead/moco中下载moco-runner-0.11.0-standalone.jar,启动它的前提是需要搭建好Java的开发环境,下来我们简单的编写⼀个登录的,⻅编写的login.json字符串:

[{"request":{"method":"post","uri":"/login","json":{"username":"admin","password":"admin","roleID":22}},"response":{"json":{"username":"wuya","userID":22,"token":"asdgfhh32456asfgrsfss"}}}
]

 下来来启动具体的moco的服务信息,启动的命令为:

java -jar moco-runner-0.11.0-standalone.jar http -p 12306 -c login.json#启动后输出的信息为:
16 ⼗⽉ 2021 18:36:51 [main] INFO  Server is started at 12306
16 ⼗⽉ 2021 18:36:51 [main] INFO  Shutdown port is 53659

下来我们调⽤下该模拟的请求信息,使⽤的⼯具是PostMan,具体发送请求后就会返回我们模拟的信息,具体如下;

 ⼀般⽽⾔,如果响应数据是很多的情况下,其实也是可以分离到JSON⽂件的,⽐如针对上⾯的案例,可以把响应数据分离到其他的JSON⽂件的,那么具体调整后的login.json⽂件信息为:

[{"request":{"method":"post","uri":"/login","json":{"username":"admin","password":"admin","roleID":22}},"response":{"file": "login_response.json"}}
]

 ⽽login_response.json⽂件的内容就为:

{"username":"wuya","userID":22,"token":"asdgfhh32456asfgrsfss"
}

mock

moco-runner-0.11.0-standalone.jar中,通过编写json的⽂件来实现,那么我们现在来看Python之中的mock,那么怎么理解mock了,mock翻译过来就是模拟的意思,也就是说,它是将测试对象所依存的对象替换为虚构对象的库,该虚构对象的调⽤允许事后查看。在python的2.x版本中,它是属于第三⽅的库,需要单独的安装,在python3.3的版本以后,不需要单独的安装,直接导⼊就可以了。在mock中,使⽤return_value来模拟⼀个对象,来验证被测试的程序。

import  pytest
import mockclass MockPay(object):def pay(self):'''⽀付接⼝'''passdef pay_result(self):'''模拟⽀付接⼝'''result=self.pay()if result['payType']=='aliPay' and result['status']:return 'aliPay'elif result['payType']=='CMB' and result['status']==False:return 'China Merchants Bank welcomes your use'else:return 'An unknown error is required'return  result['msg']def test_aliPay():'''模拟⽀付宝⽀付⽅式'''objPay=MockPay()mockValue={'payType':'aliPay','msg':'⽀付宝','status':True}#依据object的⽅式查找需要的mock对象objPay.pay=mock.Mock(return_value=mockValue)assert objPay.pay_result()=='aliPay'
def test_cmb():'''模拟招商银⾏⽀付⽅式'''objPay=MockPay()mockValue={'payType':'CMB','msg':'China Merchants Bank welcomes your use','status':False}#依据object的⽅式查找需要的mock对象objPay.pay=mock.Mock(return_value=mockValue)assert objPay.pay_result()=='China Merchants Bank welcomes your use'
def test_unknown(mocker):'''模拟未知错误信息'''objPay=MockPay()mockValue={'payType':'wuya','msg':'An unknown error is required'}#依据object的⽅式查找需要的mock对象objPay.pay=mock.Mock(return_value=mockValue)assert objPay.pay_result()=='An unknown error is required'
if __name__ == '__main__':pytest.main(["-s","-v","test_moco.py"])

 

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

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

相关文章

【tensorboard】深度学习的日志信息events.out.tfevents文件可视化工具

在用深度学习模型训练完模型后,会有一些events.out.tfevents格式的日志信息文件,如下图: 在这类文件需要用tensorboard进行打开,并且查看训练过程的信息内容。 1. tensorboard安装 pip install tensorboard -i https://pypi.do…

从零开始学Python第06课:循环结构

我们在写程序的时候,极有可能遇到需要重复执行某条指令或某些指令的场景,例如我们需要每隔1秒钟在屏幕上输出一次“hello, world”并持续输出一个小时。如下所示的代码可以完成一次这样的操作,如果要持续输出一个小时,我们就需要把…

shell:简单易明白的变量和引用

目录什么是变量shell的变量类型declare定义变量的类型根据数据类型分类根据作用域分类变量的定义shell 中的引用什么是变量 可以变化的量。本质上讲,变量就是在程序中保存用户数据的一块内存空间,而变量名就是这块内存空间的地址。 shell的变量类型 s…

“先人一步”!从华为P60看手机品牌如何找到新趋势、新玩法、新增量

对大多数人来说,换新手机是一件充满新鲜感的事,新机到手让人兴奋,可更让老蔡这样的科技发烧友们兴奋的是“比别人更快拿上新机”。朋友圈里晒图,一群人向他询问使用体验,总能让他获得一种不错的“尝鲜感”。这种现象&a…

【javaweb】SpringBoot初次体验

工具&#xff1a;idea 创建maven文件 导入依赖&#xff0c;在pom.xml中&#xff08;在spring boot的官方文档找&#xff09; <!-- spring工程中需要继承的父工程 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-b…

F1-F7快恢复二极管 SOD-123 1A 50V~1000V

之前东沃电子&#xff08;DOWOSEMI&#xff09;科普过快恢复二极管ES1A-ES1J&#xff1a;SMA封装、正向平均电流1A、最大反向恢复时间35ns、型号齐全&#xff0c;具体型号有&#xff1a;ES1A、ES1B、ES1C、ES1D、ES1E、ES1G、ES1H、ES1J&#xff0c;所对应的工作峰值反向电压分…

composer详解

一.composer简介什么是ComposerComposer 是 PHP 的一个依赖管理工具&#xff0c;它涉及 "packages" 和 "libraries",简单的说就是我们的项目通常会使用其它代码工具库&#xff0c;这时仅仅是在项目中申明依赖哪些代码工具库&#xff0c;它在每个项目的基础…

基于JavaWeb+jsp实现企业员工工资管理系统

一、项目简介 本项目是一套基于ServletJsp实现的学生成绩管理系统&#xff0c;主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目可以直接作为bishe使用。 项目都经过严格调试&#xff0…

Android开发工程师想找工作需要掌握哪些

前言 目前互联网行业越来越好&#xff0c;进入这个行业的人员也是越来越多。从开发的角度来看&#xff0c;开发的职位主要分前端&#xff0c;后端&#xff0c;客户端&#xff08;主要分为ios和android开发&#xff09;以及算法工程师等。 Android开发一直是当前互联网行业中最…

playwright--pytest-playwright、pytest-base-url插件编写用例

文章目录前言一、安装插件二、编写用例三、运行用例四、内置fixture五、全局配置base_url前言 官方的 pytest-playwright 插件可以编写端到端测试。它提供上下文隔离&#xff0c;开箱即用地在多个浏览器配置上运行。它继承了pytest框架&#xff0c;以及支持playwright的一些基…

【FPGA-DSP】第一期:DSP基础

目录 1. DSP基础 1.1 DSP基本概念 1.2 FPGA实现DSP的特点 2. DSP硬核的结构与使用 3. FPGA设计DSP技术 3.1. 浮点数与定点数的表示与转换 3.1.1. 双精度浮点数表示 3.1.2. 双精度浮点数与定点数的转换 本章作为FPGA数字信号处理的入门介绍课程&#xff0c;将介绍DSP的…

如何在Windows 10中恢复丢失的分区?

一般来说&#xff0c;未分配的空间不能在分区前直接用于存储数据&#xff0c;因此大多数Windows用户会将硬盘划分为不同的分区以存储各种数据。你可以在Windows安装期间或安装完系统后通过硬盘管理、DiskPart命令或第三方工具创建分区。 在分区丢失后&#xff0c;你会…

C的强符号/弱符号

首先上代码和结果&#xff1a; 代码&#xff1a; #include <stdio.h> int k; int k; int main() {printf("addr of k %p\n", &k);printf("value of k %d\n", k);return 0; }结果&#xff1a; addr of k 00408074 value of k 0问题&…

《辉煌优配》消费医疗加速回暖 数字化新竞赛鸣枪

“栽培牙集采将给口腔职业带来深远影响。”瑞尔齿科副总经理胡云帆3月23日承受证券时报记者采访时表明&#xff0c;资料费用下降将惠及公司运营端&#xff0c;同时激活了一大批存量客户。公司相关产品和服务价格已经开端呈现一些变动的迹象。 栽培牙费用包含栽培体费用、牙冠费…

狗都能看懂的VAE笔记

文章目录自编码器普通Auto-Encoder的问题解决的方法如何运作数学细节生成模型Auto-Encoder一直是一个非常有创造性的方向。期中的VAE变分编码器一直是我没搞懂的部分&#xff0c;在AI绘画突然火起来的时候&#xff0c;不得不搞清楚VAE了。看了很多VAE的讲解&#xff0c;没有良好…

The Shebeen——爱尔兰酒吧 NFT 来袭!

从爱尔兰神像到标志性的爱尔兰帽子&#xff0c;The Shebeen——爱尔兰酒吧 NFT 系列是一系列非常吸引的独特数字资产&#xff0c;体现了爱尔兰的精神和风俗。 The Shebeen NFT 系列均来自 The Shebeen——爱尔兰酒吧游戏体验&#xff0c;3 月 17 日至 3 月 29 日可在 The Sandb…

c/c++开发,无可避免的自定义类类型(篇八).为类妥善处理异常

目录 一、异常简述 1.1 异常是什么 1.2 异常处理概念 二、异常处理 2.1 try……catch异常处理语法 2.2 动态异常说明-throw 2.3 标准异常体系 2.4 try ...catch抛出异常对象的处理 2.5 异常捕获处理级别 2.6 抛出对象方式 2.7 try 块以及处理块内严禁跳转语法使用 2.8 异常捕…

【MySQL高级篇】 第8章_索引的创建与设计原则

第8章_索引的创建与设计原则 1. 索引的声明与使用 1.1 索引的分类 MySQL的索引包括普通索引、唯一性索引、全文索引、单列索引、多列索引和空间索引等。 从 功能逻辑 上说&#xff0c;索引主要有 4 种&#xff0c;分别是普通索引、唯一索引、主键索引、全文索引。 按照 物…

Python如何实现读写txt文件?读写txt文件的方法有哪些?

前言 又是一篇纯知识点的文章&#xff0c;现在看文章的人越来越少了&#xff0c;是都去看视频了吗 今天就来聊聊 - Python实现读写txt文件的方法 一、读写模式&#xff1a; w&#xff1a;向文件中写入内容&#xff0c;w会清空原来文本内容a&#xff1a;向文件中追加内容r&am…

sql性能优化:MS-SQL(SQL Server2012)服务器配置选项(sp_configure )对照表

sql性能优化&#xff1a;MS-SQL&#xff08;SQL Server&#xff09;服务器配置选项&#xff08;sp_configure &#xff09;对照表 2019服务器配置选项 (SQL Server) - SQL Server | Microsoft Learn 2012服务器配置选项 | Microsoft Learn 介绍 可以使用 SQL Server Managemen…