目录:导读
前言
1、mock技术的简介
1)怎么实现mock(技术很多,大的概念,各种语言都可以实现)只要能把后台逻辑模拟出来的系统就是mock技术
python,java 写后端;
python+flask/django编程 写一个简易的系统(请求响应后台服务,不需要前端)需要编码能力;
现成的mock平台 moco框架(java包) 所有的配置使用json文件(一般采用第三种,不需要代码编程技术,只要改json配置文件
2)模拟技术不同的命名
mock技术
挡板技术 —很大的概念,挡板是mock里面的一种
线下系统
沙河
沙箱测试
3)mock技术是敏捷开发的一个体现(测试提前介入推动项目进度)
4)moco介绍 (mock技术实现方法,很多)
实现mock的技术很多,这些技术中,可以分为两类,mock数据和mock服务:
mock数据:即 mock 一个对象,写入一些预期的值,通过它进行自己想要的测试。常见的有: EasyMock、Mockito 、WireMock、JMockit。主要适用于单元测试。
mock 服务:即mock 一个 sever,构造一个依赖的服务并给予他预期的服务返回值,适用范围 广,更加适合集成测试。如 moco框架。
Moco是类似一个 Mock 的工具框架,一个简单搭建模拟服务器的程序库/工具,下载就是一个JAR包。 有如下特点:
只需要简单的配置 request、response 等即可满足要求
支持 http、https、socket 协议,可以说是非常的灵活性
支持在 request 中设置 Headers , Cookies , StatusCode 等
对 GET、POST、PUT、DELETE 等请求方式都支持
无需环境配置,有 Java 环境即可
修改配置后,立刻生效。只需要维护接口,也就是契约即可 (边改边生效)
支持多种数据格式,如 JSON、Text、XML、File 等
可与其他工具集成,如 Junit、Maven等
5)moco环境搭建
我们可以直接去github上获取moco的jar包,当前版本是:V1.1.0。
地址:https://github.com/dreamhead/moco 这里展示了关于moco的介绍和源码,我们可以点击箭头 处直接下载它的jar包
java -jar moco-runner-1.1.0-standalone.jar http -p 9999 -c test.json
cmd输入前面命令,起java进程,这是开启的http协议模拟
java -jar moco-runner-1.1.0-standalone.jar https -p 9999 -c test.json
这样也可以模拟https协调
jar包的名称可根据自己下载的jar包版本来写
http代表这个模拟的是http请求
-p 9090定义是端口号
-c test.json 是我们编辑的那个json文件名(构建模拟请求需要.json文件构建,写接口请求什么样子,响应什么样子,只需要修改这个就行)
6)test.json编辑文本里面写的内容如下
{
"description":"demo1=约定URI", ----接口的描述
"request":{ ----request表示request请求的组建
"uri":"/ywt_sq"
},
"response":{ ----response响应的组建
"text":"Hello,ywt"
}
},
2、支付电商+异步接口(结合mock技术)
现在很多行业都会使用调用第三方的接口,了解支付接口有什么参数,(查看支付宝开源的对外接口)
vip对接微信接口,告诉学员什么时候上课,什么时候签到,推送信息 vip对接微信接口,第三方接口一般都是会开放的,对接微信公众号的接口
这种第三方接口都是现成的能够使用的,短信接口,微信和支付宝的接口都是现成提供使用的,不需要测试
测试支付接口:支付沙箱(就是测试环境,里面钱都是自定的,一般的第三方支付平台,支付宝的接口,
京东对应的的京东接口都是有沙箱环境的,沙盒,沙箱就是个测试环境)
项目里面可以调用这个环境,模拟扣款付款整个流程–不需要真金白银去测试。
沙箱环境是第三方支付平台推出的,除了跟真实账户去绑定,其他功能都是一模一样的,行业认可的真实度的
支付宝推出支付宝的沙箱环境,电商和第三方调用支付接口的都需要知道什么是沙箱,
也能自己从支付宝或者第三方平台库能找到整个环境,现成的
1)支付接口简易接口
路径
方式
请求参数
头
body
小额的金额支付真实环境测试的,最后调试会看一下,大额的金额支付一般都是沙箱测试
沙箱做完之后基本没什么问题,第三方支持的,除了额度其他基本都一样
2)支付接口的mock模拟:.json文件内容如下:
{
"description":"支付接口-mock", 描述
"request":{
"method":"POST", post请求
"uri":"/trade/purchase", 路径
"headers":{ 头
"Content-Type":"application/json"
},
"json":{ 请求体
"out_trade_no":"20150320010101001",
"auth_code":"28763443825664394",
"buyer_id":"2088202954065786",
"seller_id":"2088102146225135",
"subject":"Iphone6",
"total_amount":"88.88"
}
},
"response":{ 响应数据
"headers":{ 响应头
"Content-Type":"application/json"
},
"status":200, 响应状态
"json":{ json为响应体数据
"code":"40004",
"msg":"Business Failed",
"sub_code":"ACQ.TRADE_HAS_SUCCESS",
"sub_msg":"交易已被支付",
"trade_no":"2013112011001004330000121536",
"out_trade_no":"6823789339978248"
}
}
}
这就是一个支付的,实际业务层是支付,但是接口用的时候跟我们差不多
请求代码:
import requests
url="http://127.0.0.1:9999/trade/purchase"
headers={"Content-Type":"application/json"}
data={"out_trade_no":"20150320010101001",
"auth_code":"28763443825664394",
"buyer_id":"2088202954065786",
"seller_id":"2088102146225135",
"subject":"Iphone6",
"total_amount":"88.88"
}
response=requests.post(url,headers=headers,json=data)
print(response.json())
3、同步接口和异步接口(教官系统里面的接口都是同步接口)
同步接口:我给你东西,就等你东西,发请求给你,就等你响应就行ok了,不来就超时或者一直等着,请求等你响应,你不来我就等着不动了,你不动我不动
这样就很尴尬,银行办事情,前面需要拿号,号没拿到办不了事情,这是同步的,拿号操作后才能往后面走,否则走不了
异步接口:
加商品:增加归增加,增加完之后我立马增加请求发出去之后,服务端立马回一个id号(跟踪userid号)放在队列里面做的,告诉你我已经再队列里处理你的请求
后面你来查就行了,哪怕中间很慢很慢没关系,它来处理,等会来查就行了。
银行办事:三个窗口,第一个窗口办完之后给凭证,然后告诉我看到这里面好了就来拿东西。
体检:很多项目,验完血之后给个单子,让你等多少时间来拿化验报告就行,
接着做下面的项目 这就是异步
(工作人员化验你的血液),我们正常去体检其他项目,等做完之后看到结果出来去拿结果就行了,定时让朋友去问问定时查询体检动作–不等
很重要:现在教官系统都是同步的,发一个请求等一个,如果请求没有响应会发现我们一直等着那边不会释放,请求没有结束是不会释放的,采取异步操作
理解异步和同步操作
异步一般两个步骤:一个操作,一个是get的
请求接口;
get接口:get结果-查result结果;
4、mock模拟技术+异步接口代码
订单的例子:
先创建订单,订单有没有创建成功需要等待后台服务响应完之后才能知道结果。
先创建订单接口,创建完之后后面又有一个获取订单接口 两步:一步是获取订单接口,一步是我们创建订单接口(两个操作)
异步的,我增加订单归增加,增加完之后后台给我返回一个id号,追踪的id号,后面查就行。
查到了就是增加订单成功,不需要等订单增加的结果,保证接口定时查询就行—这就是所谓的异步操作
工作里面很多—高性能,体验度好的都是异步接口,不是同步的
异步接口创建成功会有响应:响应并不是一个是否成功,异步一般不会直接返回结果的。
只告诉你消息我已经放在队列里面处理了,告诉你队列号,或者处理的id号,你等结果就行
以后根据id等号码查询就知道状态是否完成
1)mock的json文件内容
[
{
"description":"创建订单接口-mock",
"request":{
"method":"POST",
"uri":"/api/order/create/",
"headers":{
"Content-Type":"application/json"
},
"json":{
"user_id": "sq123456",
"good_id": "20200818",
"num": 1,
"amount": 200.6
}
},
"response":{
"headers":{
"Content-Type":"application/json"
},
"status":200,
"json":{
"order_id": "6666"
}
}
},
{
"description":"查询订单接口-mock",
"request":{
"method":"GET",
"uri":"/api/order/get_result/", #查询不是json,不写headers,不写就是表单,get没法用json去做,不好做,去掉headers,get请求的params不能写成json
"queries":{
"order_id": "6666"
}
},
"response":{
"headers":{
"Content-Type":"application/json"
},
"status":200,
"json":{
"user_id": "sq123456",
"good_id": "20200818",
"num": 1,
"amount": 200.6
}
}
}
]
2)mock技术+异步接口实例代码
Host='http://127.0.0.1:9999'
import requests
import time
#异步接口(数据和结果不在一个接口里面,分开几个接口来做的,这个接口只表明提交成功的,接口到底有没有成功需要看后面)
#1增加订单操作
def create_order():
url=f'{Host}/api/order/create/'
payload={
"user_id": "sq123456",
"good_id": "20200818",
"num": 1,
"amount": 200.6
}
reps=requests.post(url,json=payload) #json传递参数默认带"Content-Type":"application/json"
return reps.json() #立马返回一个追踪的操作id号--给后续的查询使用的,
"""2:查询订单接口,异步接口,只做查询功能,把id的订单号传进去查询
查询和创建订单接口不同,异步,增加完之后拿到id号,后面定时查询就行,其他不需要管
异步接口肯定不是一步,2步或者两步以上,正常的也就2.3步,看接口复杂程度,一个就是同步接口,发接口等结果这种就是同步的
必须等结果,不等没有结果
异步概念:有些接口很慢的。创建一个订单需要很长时间响应,同步体验感很差,等半天--异步性能高
办业务点击提交时候立即出现您的业务已经提交然后两分钟之后过来显示,很多软件这样搞得
比如贷款申请房产申请就是这么做的,出结果的这几分钟用户可以进行其他操作,到时候来查询结果就行
比如支付宝转账"""
def get_order_result(orderid,timeout=20,interval=1): #超时时间:timeout=10,轮巡周期:interval=1 1s查询一次
#这是个机制,不可能查一天,需要定时查询,隔多少时间查一次,然后多少时间没有查到就认为结果失败了 轮巡思路
'''查询订单接口,查询结果,一般有个超时机制,不是无限等待'''
#构建查询的接口代码,查询接口并不是立马就回结果,需要轮询,需要一直发,隔多少查一次,查到结束
url=f"{Host}/api/order/get_result/"
payload={
"order_id": orderid #做成形参,查某个写某个,方法就能通用了
}
stattTime=time.time() #开始时间
endTime=stattTime+timeout #结束时间等于开始时间+超时时间,时间到了就要停止
cnt=1 #轮询的次数
#轮巡操作--是需要定时发送查询请求的,
while time.time() < endTime: #如果当前时间小于结束时间,一直轮询
reps=requests.get(url,params=payload)
time.sleep(interval) #发了之后需要查,当前时间小于结束时间的时候一种查询,发一次休眠个轮询时间,
#发一次隔多少时间发一次,定时轮询,定时查询
print(f'当前第{cnt}次查询')
cnt=cnt+1
if reps.json(): #判断是否有数据返回,如果有返回值的话,停止轮询,查到就退出.如果整个时间没有查到,
break
else: #如果时间到了都没有查询到,返回空的数据
return None
return reps.text
"""上面就是一个简单异步接口操作,创建得到一个订单id号,但是查询里面设置查询周期和超时机制 理论就是这样的
时间没到就定时查询,时间到了就退出来,wihle else操作,while条件运行完了没有return话,那么就会到else里面return None空
wihle else:如果while超时还是没有返回值,那么就回进入else代码块,return None,后面的return reps.text不会执行
最后不管怎么样把结果返回去return reps.text 怎么都有值的
轮询有结果才会退出,没有不能退出,时间没到不能返回为空,直到超时才结束
要求查询10s,10s内一种查询,每隔ls查询一次, 10s过了后
工作很常见的,直到所有的时间走完所有timeout时间结束之后我们才决定不查,只要时间没到我们一种查,每隔1s查一次,查到结果结束
思路分析:直到怎么封装这种异步接口
这种场景在我们公司里面特别多,
异步接口:类似体检,验血,验血完后,给一个小票,编号,拿到编号不需要你在这边等,去检查其他体检项目
可以让朋友看一下验血好了没有,当id号完成有报告了再回来取结果, 多次查询,每做完一个项目看一次,轮询查结果
不影响工作,正常操作就行,但是保证查询接口一直在跑在查询,省的阻塞不动
同步接口:一手交钱一手交货,给钱了不给货,死等不动,同步的
订单和申请的操作一般很多都素异步接口,需要等的
如何模拟这种情况:两个接口
1:创建订单接口,整个服务端采用mock技术来做,mock技术做的时候创建好mock,发送请求,得到追踪的id号
增加订单完成后可以干其他的事情了,但是我后面可以轮询取查询,轮询周期自己设置一下,性能好很多
2:get_order_result接口去查询订单结果,轮询异步操作封装函数特点:1:查多少时间timeout 2:轮询周期interval
多少时间轮询一次
构建查询请求url,payload,stattTime开始时间,endTime结束时间根据当前时间+超时时间
然后里面做个循环while time.time() < endTime:然后每次循环都去requests发出请求,然后轮询1s(形参对外开放,可以修改)
查询周期特点:如果查询周期范围内一旦有结果,就结束循环,break,然后 return reps.text查询结果
如果到超时时间也没有查询到,while循环已经退出了,这时候没有结果的,返回空,
可以做断言assert断言返回结果---pytest判别响应的结果,没有区别--查询结果需要轮询操作--根据接口本身的特性来
设置合理的周期和频率,
模板 """
if __name__ == '__main__':
#1:创建订单--获取id
orId=create_order()["order_id"]
print(get_order_result(orId, timeout=20))
3)mock 技术的局限性:
自动化需要环境初始化和环境清除,mock做不了,mock只能针对调试接口逻辑比较合适,做不了接口的关联性,做不了后台服务,比如要清除添加的设备,或者添加设备初始化操作搞不定
4)token通过接口获取的,不算异步,死等token值,
异步:第一个请求立马会有数据回给你,但是这个数据不是我们想要的数据,叫异步,发的一个临时的号码牌,去干其他的操作,等数据这个对应的队列结束完之后会返回数据,查这个id号-
获取token,cookie都是同步的,在一些业务逻辑里面会有一些异步的操作
不是关联就是异步的,不仅仅是是关联,业务操作上的问题
5、基于复用的二次封装:requests与log
接口测试失败了,是测试的问题还是开发的问题
请求报错了,怎么去排查,谁的问题
代码测试:必须保证自己的代码没有bug
#日志处理,日志库
import logging
import os
log_path='.\log\log.log'
def create_log(log_path):
logger=logging.getLogger(os.path.split(log_path)[1]) #创建一个日志对象
#os.path.split(log_path)[1]指定日志名字
logger.setLevel(logging.INFO) #设置日志记录级别 info及以上的级别才会记录
fh = logging.FileHandler(log_path,encoding='utf-8') #打开指定的文件,并将其作为日志记录的位置---日志记录流
#记录日志文件的位置 一般做配置文件
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
#定义日志输出格式 设置asctime时间
#name 文件名 日志级别levelname
fh.setFormatter(formatter) #当定义的格式和日志流绑定生效
logger.addHandler(fh) #往logger中对象添加输出方式
return logger #最终操作日志通过logger对象
apiLog=create_log(r'.\log\api.log') #创建一个日志对象apiLog
def decoratelog(func): #传函数名称
'''日志装饰器,func是被装饰函数的函数名,函数功能是'''
def wrapper(*args,**kwargs):
logger=create_log(log_path)
try:
func(*args,**kwargs)
except Exception as e:
#记录异常
err=f"异常发送在:{func.__name__},内容:{e}" #查看异常发生的函数名字
logger.exception(err) #特别适合记录异常信息的一个方法
return wrapper
if __name__ == '__main__':
log_path = '.\log\log.log'
lo=create_log(log_path)
lo.info('这一行是测试日志')
import requests
from day1.my_log import apiLog #导入apiLog对象
from day1.my_log import decoratelog
#基于接口请求复用的一个二次封装
class myRequests: #重写requests,
def __init__(self,url):
self.session=requests.session() #session这个类可以帮忙记住一些持久性的信息:cookie,连接池,配置
#可以记录每一次接口请求的cookie
self.url=url #path:url请求路径
self.timeout=10 #超时时间
self.errorMsg="" #错误消息,初始化空的字符串
@decoratelog #装饰器,当尝试调用被装饰函数的时候,如果发生异常,捕捉异常并记录下来
def post(self, bodydata=None, bodyjson=None, **kwargs):
#针对原始post的一个二次封装,重写post函数
response=''
try:
response=self.session.post(self.url, data=bodydata, json=bodyjson, timeout=self.timeout,**kwargs)
apiLog.info('请求参数:%s'% bodydata if bodydata else bodyjson)
#三元运算符 如果bodydata为真就填写bodydata,如果bodydata为假,走bodyjson
apiLog.info('请求结果:%s'% response.text) #记录请求结果
except Exception as e: #报错捕捉e错误信息
self.errorMsg=str(e)
raise Exception(f'http请求异常,异常信息\n{self.errorMsg}',)
return response
if __name__ == '__main__':
r=myRequests('https://api.binstd.com/shouji/query')
payload = {
"appkey":"your_appkey_here",
"shouji":"18163606916"
}
r.post(bodydata=payload)
最全Python自动化测试进阶之路视频教学 (全集)
下面是我整理的2025年最全的软件测试工程师学习知识架构体系图 |
一、Python编程入门到精通
二、接口自动化项目实战
三、Web自动化项目实战
四、App自动化项目实战
五、一线大厂简历
六、测试开发DevOps体系
七、常用自动化测试工具
八、JMeter性能测试
九、总结(尾部小惊喜)
人生最动人的风景,往往藏在最难攀爬的高处。当你觉得力竭时,请记住:每一次坚持都在雕刻更强大的自己。别问路有多远,只管迈步向前;别怕山有多高,向上攀登就是答案!
你体内沉睡着改变世界的力量!每个清晨都是改写命运的新机会,每次挫折都是精心包装的礼物。当全世界都在说"不可能"时,正是你证明"可能"的最好时机!