目录
一、代码实现自动化理论及流程
二、脚本实现的理论和准备工作
1、抽取功能转为自动化用例
2、搭建环境(测试工具)
3、搭建目录结构
三、登录接口脚本实现
1、代码编写
1️⃣api目录
2️⃣script目录
2、断言
3、参数化
1️⃣编写数据存储文件:json文件
2️⃣编写读取数据工具:read_json()
3️⃣参数化引用:parameterize
一、代码实现自动化理论及流程
🔴代码编写脚本和工具实现脚本区别是什么?
- 代码:
- 优点:代码灵活方便
- 缺点:学习成本高
- 工具:
- 优点:易上手
- 缺点:灵活度低,有局限性。
- 总结:
- 功能脚本:工具
- 自动化脚本:代码
🔴代码接口自动化怎么做的?
- 第一步:(概述)python+request+unittest;
- 第二步:(具体描述)封装、调用、数据驱动、日志、报告;
- 第三步:(举例)api\scripts\data\log\report\until\...;
二、脚本实现的理论和准备工作
使用代码编写自动化脚本的流程:
- 1、抽取功能用例转为自动化⽤例。
- 2、搭建环境(测试工具相关的)
- 3、搭建目录结构
- 4、编写脚本
- 5、执行脚本
- 6、配置持续集成
1、抽取功能转为自动化用例
去掉了有bug的用例、以及“请求后台投资响应失败(密码为空)”的用例(改用例需要借钱和投资双方私下协商密码)
2、搭建环境(测试工具)
①python、pycharm、requests、pymysql、parametrize
②jenkins、jdk
提示:由于编写的自动化脚本,而自动化脚本编写之前功能已测试完毕,所以不需要在单独搭建项目环境。
3、搭建目录结构
三、登录接口脚本实现
1、代码编写
1️⃣api目录
把需要测的接口放在该目录
url设置成私有变量,只能在该类内部调用。
此处这样做只是因为url实际上只会在该登陆注册模块内部使用,外面没必须用到,设置私有,外部调用方法的时候。看着干净
from config import HOST
class ApiRegisterLogin:
# 有几个接口就封装几个方法
#初始化
def __init__(self, session):
# 获取session对象
self.session = session
# 图片url
# 图片验证码url
self.__url_img_code = HOST + "/common/public/verifycode1/{}"
# 短信验证码url
self.__url_phone_code = HOST + "/member/public/sendSms"
# 注册Lr1
self.__url_register = HOST + "/member/public/reg"
# 登录url
self.__url_login = HOST + "/member/public/login"
# 登录状态url
self.__url_login_status = HOST + "/member/public/islogin"
# url
# 1、获取图⽚验证码接⼝ 封装
def api_img_code(self,random):
return self.session.get(url=self.__url_img_code.format(random))
# 2、获取短信验证码接⼝ 封装
def api_phone_code(self,phone,imgVerifyCode):
data = {
"phone": phone,
"imgVerifyCode": imgVerifyCode,
"type": "reg"
}
return self.session.post(url=self.__url_phone_code,data=data)
# 3、注册接⼝ 封装
def api_register(self,phone,password,verifycode,phone_code):
data = {
"phone": phone,
"password": password,
"verifycode": verifycode,
"phone_code": phone_code,
"dy_server": "on",
"invite_phone": ""
}
return self.session.post(url=self.__url_register,data=data)
# 4、登录接⼝ 封装
def api_login(self,keywords,password):
data = {
"keywords": keywords,
"password": password
}
return self.session.post(url=self.__url_login, data=data)
# 5、查询登录状态接⼝ 封装
def api_login_status(self):
return self.session.post(url=self.__url_login_status)
2️⃣script目录
调用封装的接口,开展测试工作
下面测试用例的内容目前只是测试一下api文件中封装的接口能不能用,后面还要改。
import unittest
import requests
from api.api_register_login import ApiRegisterLogin
class TestRegisterLogin(unittest.TestCase):
# 初始化
def setUp(self) -> None:
# 获取session对象
self.session =requests.Session()
# 获取ApiRegisterLogin实例
self.reg = ApiRegisterLogin(self.session)
# 结束
def tearDown(self) -> None:
# 关闭session对象
self.session.close()
#1、获取图片验证码接口 测试
def test01_img_code(self):
# 调用图片验证码接口
r = self.reg.api_img_code(234)
# 查看响应状态码
print(r.status_code)
#2、获取短信验证码接口 测试
def test02_phone_code(self,phone=17612341111,imgVerifyCode=8888):
# 1、调用获取图片验证码接口 -- 目的:让session对象记录cookie
# 调用接口后session会自动记录cookie
self.reg.api_img_code(234)
# 2、调用短信验证码接口
r = self.reg.api_phone_code(phone=phone,imgVerifyCode=imgVerifyCode)
# 3、查看响应结果
print(r.json())
#3、注册接口 测试
def test03_register(self,phone=17612341111,imgVerifyCode=8888,password="win56",phone_code=666666):
# 1、图片验证码接口
self.reg.api_img_code(234)
# 2、短信验证码接口
self.reg.api_phone_code(phone=phone, imgVerifyCode=imgVerifyCode)
# 3、注册接口
r = self.reg.api_register(phone=phone,password=password,verifycode=imgVerifyCode,phone_code=phone_code)
# 4、查看结果
print(r.json())
#4、登录接口 测试
def test04_login(self,keywords=17612341111,password="win56"):
# 1、调用登录
r = self.reg.api_login(keywords=keywords,password=password)
# 2、查看结果
print(r.json())
#5、查询登录状态接口 测试
def test05_login_status(self):
# 调用登录擦口
self.reg.api_login(keywords=17612341111, password="win56")
# 调用查询登录状态接口
r = self.reg.api_login_status()
# 看结果
print(r.json())
2、断言
说明:判断程序执⾏实际结果是否符合预期结果
示例:
实际需要将api_register_login.py中的每个测试用例都做异常处理,下面只是以查询登录接口中的异常捕获为例。
中的完整代码后续补充。
try:
# 调⽤登录接⼝
self.reg.api_login(keywords="13600001111", password="test123")
# 调⽤查询登录状态接⼝
r = self.reg.api_login_status()
# 看结果
self.assertIn(expect_text, r.text)
except Exception as e:
# ⽇志
print(e)
# 抛异常
raise
# 提示:捕获异常的⽬的是为了将错误信息记录下来,捕获信息完成后,必须抛出异常
【提示】:捕获异常的目的是为了将错误信息记录下来,捕获信息完成后,必须抛出异常
3、参数化
步骤:
- 1、编写数据存储⽂件 json
- 2、编写读取⼯具⽅法 read_json()
- 3、使⽤参数化组件进⾏引⽤ parametrize
1️⃣编写数据存储文件:json文件
心得:
1、根据模块来新建json文件(1个模块1个json⽂件)
2、最外侧使用{},模块下几个接口,编写几个key,值为列表
3、列表值中,有几组数据,就写几个{}
4、每组数据{}中,组成格式:说明+参数+预期结果
{
"img_code": [
{
"desc": "获取图片验证码成功(随机小数)",
"random": 0.123,
"expect_code": 200
},
{
"desc": "获取图片验证码成功(随机整数)",
"random": 123,
"expect_code": 200
},
{
"desc": "获取图片验证码失败(随机数为空)",
"random": "",
"expect_code": 404
},
{
"desc": "获取图片验证码失败(随机数为字符串)",
"random": "123hello",
"expect_code": 400
}
],
"phone_code": [
{
"desc": "获取短信验证码成功",
"phone": "13600001111",
"imgVerifyCode": 8888,
"expect_text": "发送成功"
},
{
"desc": "获取短信验证码成功",
"phone": "13600001111",
"imgVerifyCode": 8889,
"expect_text": "验证码错误"
}
],
"register": [
{
"desc": "注册成功(必填参数)",
"phone": 13600001111,
"password": "test123",
"verifycode": 8888,
"phone_code": 666666,
"expect_text": "注册成功"
},
{
"desc": "注册失败(图片验证码错误)",
"phone": 13600001112,
"password": "test123",
"verifycode": 8889,
"phone_code": 666666,
"expect_text": "验证码错误"
},
{
"desc": "注册失败(短信验证码错误)",
"phone": 13600001112,
"password": "test123",
"verifycode": 8888,
"phone_code": 666667,
"expect_text": "验证码错误"
},
{
"desc": "注册失败(手机号已存在)",
"phone": 13600001111,
"password": "test123",
"verifycode": 8888,
"phone_code": 666666,
"expect_text": "已存在"
}
],
"login": [
{
"desc": "登录成功",
"keywords": 13600001111,
"password": "test123",
"expect_text": "登录成功"
},
{
"desc": "登录失败(密码为空)",
"keywords": 13600001111,
"password": "",
"expect_text": "不能为空"
},
{
"desc": "登录失败(解锁)",
"keywords": 13600001111,
"password": "error123",
"expect_text": "登录成功"
}
],
"login_status": [
{
"desc": "查询登录状态(已登录)",
"status": "已登录",
"expect_text": "OK"
},
{
"desc": "查询登录状态(已登录)",
"status": "未登录",
"expect_text": "未登"
}
]
}
2️⃣编写读取数据工具:read_json()
import json
import os
from config import DIR_PATH
def read_json(filename,key):
# 拼接读取文件的完整路径
# os.sep是动态获取/ \
filepath = DIR_PATH + os.sep + "data" + os.sep +filename
arr = []
with open(filepath,"r",encoding="utf-8") as f:
for data in json.load(f).get(key):
arr.append(list(data.values())[1:])
return arr
if __name__ == '__main__':
# 测试一下能不能读取到数据
print(read_json("register_login.json","img_code"))
# 读取的数据为:[[0.123, 200], [123, 200], ['', 404], ['123hello', 400]]
3️⃣参数化引用:parameterize
难点1:错误次数锁定
难点2: 查询登录状态,不同结果。
【注意】由于parameterized的自身bug,运行测试用例必须是点击到测试用例所在的类名右键运行。如果想单独运行某个接口用例,则把其他接口代码先注释掉。
import unittest
from time import sleep
import requests
from api.api_register_login import ApiRegisterLogin
from parameterized import parameterized
from util import read_json
class TestRegisterLogin(unittest.TestCase):
# 初始化
def setUp(self) -> None:
# 获取session对象
self.session =requests.Session()
# 获取ApiRegisterLogin实例
self.reg = ApiRegisterLogin(self.session)
# 结束
def tearDown(self) -> None:
# 关闭session对象
self.session.close()
#1、获取图片验证码接口 测试
@parameterized.expand(read_json("register_login.json","img_code"))
def test01_img_code(self,random,expect_code):
try:
# 调用图片验证码接口
r = self.reg.api_img_code(random)
# 查看响应状态码
# print(r.status_code)
self.assertEqual(expect_code,r.status_code)
except Exception as err:
# 日志
print(err)
# 抛异常
raise
#2、获取短信验证码接口 测试
@parameterized.expand(read_json("register_login.json", "phone_code"))
def test02_phone_code(self,phone,imgVerifyCode,expec_text):
try:
# 1、调用获取图片验证码接口 -- 目的:让session对象记录cookie
# 调用接口后session会自动记录cookie
self.reg.api_img_code(234)
# 2、调用短信验证码接口
r = self.reg.api_phone_code(phone=phone,imgVerifyCode=imgVerifyCode)
# 3、查看响应结果
# print(r.json())
self.assertIn(expec_text,r.text) # 使用text提取结果是更方便,json还要根据键找值
except Exception as err:
# 日志
print(err)
# 抛异常
raise
#3、注册接口 测试
@parameterized.expand(read_json("register_login.json", "register"))
def test03_register(self,phone,password,imgVerifyCode,phone_code,expec_text):
try:
# 1、图片验证码接口
self.reg.api_img_code(234)
# 2、短信验证码接口
self.reg.api_phone_code(phone=phone, imgVerifyCode=imgVerifyCode)
# 3、注册接口
r = self.reg.api_register(phone=phone,password=password,verifycode=imgVerifyCode,phone_code=phone_code)
# 4、查看结果
# print(r.json())
self.assertIn(expec_text,r.text)
except Exception as err:
# 日志
print(err)
# 抛异常
raise
#4、登录接口 测试
@parameterized.expand(read_json("register_login.json", "login"))
def test04_login(self,keywords,password,expec_text):
try:
i = 0
r = None
if "error" in password:
while i <3:
r=self.reg.api_login(keywords,password)
i+=1
# 锁定断言
print("账号密码输错3次,账号锁定:",r.text)
self.assertIn("锁定",r.text)
# 暂停60秒
sleep(60)
r = self.reg.api_login(keywords=17612341111, password="win56")
self.assertIn(expec_text,r.text)
else:
# 1、调用登录
r = self.reg.api_login(keywords,password)
# 2、查看结果
# print(r.json())
self.assertIn(expec_text, r.text)
except Exception as err:
# 日志
print(err)
# 抛异常
raise
#5、查询登录状态接口 测试
@parameterized.expand(read_json("register_login.json", "login_status"))
def test05_login_status(self,status,expec_text):
try:
if status == "已登录":
# 调用登录擦口
self.reg.api_login(keywords=17612341111, password="win56")
# 调用查询登录状态接口
r = self.reg.api_login_status()
# 看结果
# print(r.json())
self.assertIn(expec_text, r.text)
except Exception as err:
# 日志
print(err)
# 抛异常
raise
【总结】目前为止已经写的文件,文件内容上面均给出了代码