注:本节教材内容,与上两期推送的《教材连载:蜗牛进销存项目实战(一)》、《
教材连载:利用Requests库完成“蜗牛进销存”的登录功能》为一个项目实战内容。
回顾上节内容,请点击:教材连载:蜗牛进销存项目实战(一)
教材连载:利用Requests库完成“蜗牛进销存”的登录功能
利用Requests库新增会员
1.发送请求
下图是新增会员的功能,填写正确的字段后即可新增成功。
通过对该请求的分析,我们依然构造正文,并发送新增的POST请求。
import requests # 构造请求正文 addData = {'customername':'小蜗牛','customerphone':'13500000000','childsex':'女','childdate':'2018-05-18','creditkids':'100','creditcloth':'200'} # 发送请求 r = requests.post("http://localhost:8080/WoniuSales/customer/add",addData) # 输出响应正文 print(r.text) |
结果并不如我们所料,返回的是一个错误的页面,并且通过页面的查询也没有出现新增的会员“小蜗牛”,这里的代码和登录的POST请求一样,为什么不能达到类似的效果?
<html><head><title>500 Internal Server Error</title></head><body bgcolor='white'><center><h1>500 Internal Server Error</h1></center><hr><center><a href='http://www.jfinal.com?f=ev-3.2' target='_blank'><b>Powered by JFinal 3.2</b></a></center></body></html> |
2.定制请求头cookie
回顾前面的内容,Http协议是一种无连接无状态的协议,当用户处理登录状态时我们才可以进行后续的操作,那通过协议的角度,这里我们并没有保持登录的状态,所以添加上对应的cookie值即可。
import requests # 定制cookie cookie = {'Cookie':'JSESSIONID=8C61635F9F68E2E068F627A4927494BA'} # 构造请求正文 addData = {'customername':'小蜗牛','customerphone':'13500000000','childsex':'女','childdate':'2018-05-18','creditkids':'100','creditcloth':'200'} # 发送请求 r = requests.post("http://localhost:8080/WoniuSales/customer/add",addData) # 输出响应正文 print(r.text) |
运行结果正确。
add-successful |
需要注意的是,这里的cookie值由于是我们已经预先在浏览器上进行了登录,直接复制了一个有效的cookie值来使用,所以能够正常操作成功,但实际情况是,我们不可能每次都预先登录好,再来编写Python程序,这显然是不科学的。
3.实时获取cookie
由于cookie值在登录后才有效,所以我们的思路是:对系统先进行登录,再从登录的响应里获取到cookie,并将此cookie保存下来,供其他请求使用,代码如下。
import requests # 获取登录后的响应 loginData = {'username':'boss','password':'boss123','verifycode':'1111'} loginRes = requests.post("http://localhost:8080/WoniuSales/user/login",data=loginData) # 构造请求正文 addData = {'customername':'小蜗牛02','customerphone':'13200000000','childsex':'女','childdate':'2018-05-18','creditkids':'100','creditcloth':'200'} # 发送请求,重点是添加cookies参数 addRes = requests.post("http://localhost:8080/WoniuSales/customer/add",data=addData,cookies=loginRes.cookies) print(addRes.text) |
这里的重点是:登录过后获取到的响应是loginRes,再将此响应的cookies值作为post请求的参数发送到服务器,服务器经过校验,确认此cookie有效,则新增成功。同样的,我们也可以通过会员管理的查询功能查看到“小蜗牛02”已新增成功。这样一来,当我们进行测试时,不用每次都去手工复制cookie的值,整个程序的流程更加通畅。
利用Requests库对新增会员进行测试
前面的工作已经让我们可以正常的发送请求,这也为接下来的测试打下了良好的基础。有的读者在疑惑:难道前面做了这么多工作还没有开始测试?不要忘了,测试最重要的一个步骤,对结果进行断言,虽然我们可以利用肉眼来观察结果进而得出结论,但自动化最主要的目的之一就是为了解放人力,这显然是与其相悖的。
1.理解接口文档
在实际项目中,设计一个接口之前,需要经过讨论确定接口的规格,以便于后续的团队协作,开发人员会基于此文档去编写接口,测试人员也将其作为接口测试的重要依据。所以接口文档对测试人员来说非常重要,也可视为接口测试的测试需求。下面我们将展示会员管理的接口文档。
接口名称 | 会员管理新增接口 |
URL地址 | http://localhost:8080/WoniuSales/customer/add |
调用方式 | POST |
传入参数 | customername:必填,会员姓名,长度为1-20个字符之间。 |
customerphone:必填,会员手机,不能重复,纯数字,长度需为11位。 | |
childsex:必填,会员性别,只允许“男”或“女”。 | |
childdate:必填,会员生日,为年月日格式:xxxx-xx-xx。 | |
creditkids:非必填,母婴积分,纯数字默认为0。 | |
creditcloth:非必填,童装积分,纯数字默认为0。 | |
返回响应 | add-successful:添加成功。 |
already-added:重复添加。 | |
add-failed:添加失败。 |
2.设计接口测试用例
根据接口测试文档,利用常规的等价类边界值等设计方法,很容易设计出以下一些测试用例。
当然实际情况下设计的用例远远不止这些,我们还有很多的测试点需要去覆盖到,仅仅是一个手机号还包括长度、是否纯数字等验证。由于用例设计并不是本节的重点且篇幅所限,这里仅仅列出一小部分,余下的请读者自行补充。
另外需要注意的是,这里的验证点有两个:
(1) 状态码,表示服务器对该请求是否正确回应。
(2) 响应正文,服务器返回的响应内容是否符合我们的预期。
上面的两个方面是完全不同的两回事,比如我们让一位同学回答问题,他正常回应我了,这是状态码,但他的答案正不正确,这是响应正文。初学时往往将这两者混淆,要注意分别理解。
3.开始测试
正式设计测试代码之前,我们先思考几个问题,通过对这几个问题的解答,更有助于理清思路。
(1) 会员新增的功能执行都需要借助cookie,所以我们应该封装一个函数getCookie()来进行处理,减少代码的冗余度。
(2) 每次测试发送的请求都是调用Requests的相关方法,核心本质一样,不同的只是请求的数据和断言的验证码与响应正文而已,所以我们同样封装一个函数testAdd(),并且设计好其形参。
(3) 断言的时候需要同时满足验证码与响应正文都一致才通过。
import requests # 获取cookie def getCookie(): loginData = {'username':'boss','password':'boss123','verifycode':'1111'} loginRes = requests.post("http://localhost:8080/WoniuSales/user/login",data=loginData) return loginRes.cookies # 发送post请求 def testAdd(data, expectedCode, expectedRes): cookies = getCookie() # 发送请求,重点是添加cookies参数 addRes = requests.post("http://localhost:8080/WoniuSales/customer/add",data=data, cookies=cookies) # 对响应码和响应正文断言 print('############# 开始测试 ###############') if expectedCode == addRes.status_code and expectedRes == addRes.text: print("测试用例通过!") else: print('测试用例失败!') print("状态码:" + "预期 - " + str(expectedCode) + ",实际 - " + str(addRes.status_code)) print("响应:" + "预期 - " + expectedRes + ",实际 - " + addRes.text) print('############# 结束测试 ###############') |
上面的代码分别实现了获取cookie和测试执行的功能,即两个函数,后续我们只需要设计不同的测试数据、预期的响应码、预期的响应正文即可。这里只简单列出三条测试用例,方便观察结果。
# 测试用例:所有参数正确 d = {'customername':'张明明','customerphone':'13300000000','childsex':'男','childdate':'2016-04-09','creditkids':'100','creditcloth':'200'} expCode = 200 expRes = 'add-successful' testAdd(d,expCode,expRes) # 测试用例:缺少姓名 d = {'customerphone':'13300000003','childsex':'男','childdate':'2016-04-09','creditkids':'100','creditcloth':'200'} expCode = 200 expRes = 'add-failed' testAdd(d,expCode,expRes) # 测试用例:手机号重复 d = {'customername':'王雪琳','customerphone':'13300000000','childsex':'女','childdate':'2012-11-14','creditkids':'10','creditcloth':'200'} expCode = 200 expRes = 'already-added' testAdd(d,expCode,expRes) |
运行结果如下。如果系统没有问题,那么应该三条测试用例均通过,但实际情况是第二条测试用例失败,原因已经输出,我们预期状态码是200,但实际情况返回的状态码是500,说明请求没有得到服务器正常的回应,与需求文档不符合,那么我们应该认为这是一个Bug并反馈给开发人员进行修复。
############# 开始测试 ############### 测试用例通过! ############# 结束测试 ############### ############# 开始测试 ############### 测试用例失败! 状态码:预期 – 200,实际 - 500 响应:预期 - add-failed,实际 - <html><head><title>500 Internal Server Error</title></head><body bgcolor='white'><center><h1>500 Internal Server Error</h1></center><hr><center><a href='http://www.jfinal.com?f=ev-3.2' target='_blank'><b>Powered by JFinal 3.2</b></a></center></body></html> ############# 结束测试 ############### ############# 开始测试 ############### 测试用例通过! ############# 结束测试 ############### |
接下来一周会陆续推送进销存项目实战的其他内容:
(四)接口测试框架整合。
为了答谢大家对蜗牛学院的支持,蜗牛学院将会定期对大家免费发放干货,敬请关注蜗牛学院的官方微信。