前言:本文主要介绍在企业使用Python搭建接口自动化测试框架,数据驱动读取excel表里的数据,和数据库方面的交互,包括关系型数据库Mysql和非关系型数据库MongDB,连接数据库,读取数据库中数据,最后输出完整的测试报告
前面,已经学习了如何用SpringBoot写接口以及与Mysql数据库进行交互,具体可查阅下面的这篇博客
(MVC架构)SprintBoot+html/css/js+mybatis的demo_MRJJ_9的博客-CSDN博客
本次搭建接口自动化框架的gitee仓库地址
interface_auto_test: Rquests+Pytest+Allure
目录
搭建流程图
搭建前的准备工作
request库发送请求
数据驱动
Python与数据库的交互
Python+Mysql
Python+MongDB
输出Allure报告
项目结构
总结
流程图
接口自动化测试搭建流程
先写登录接口,接口数据与Mysql+Mongo进行交互,启动项目后,使用Python开始搭建整个测试框架
搭建前的准备工作
在搭建整套接口自动化测试流程前,要有开端提到的接口测试的范围,与数据库的交互,明白业务的逻辑,接口请求类型是什么,传参是什么,预期返回是什么
这里简单写了一个登录的接口,传入的邮箱手机号,密码必须符合一定的限制条件,否则不能登录成功
关于正则表达式,参考了下面的文章
什么是正则表达式,怎么写,使用场景等都在这里了 - 知乎 (zhihu.com)
正则表达式(常用的)_/^1[3456789]\d{9}$/_Oxygen_liu的博客-CSDN博客
JAVA 手机号码格式验证,使用正则表达式_java 正则手机号195_Steven Jon的博客-CSDN博客
JAVA 电子邮箱格式验证,使用正则表达式_java邮箱正则表达式_Steven Jon的博客-CSDN博客
JAVA正则表达式校验密码必须是包含大小写字母、数字、特殊符号的8位以上组合____NULL的博客-CSDN博客
package com.example.interfaceautotest.controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class Login {
@PostMapping(value = "/login", produces = "application/json")
public String Login(String usr, String pw) {
//加入业务判断规则,用户名只能输入手机号和注册的邮箱
//usr可以输入手机号 也可以输入邮箱
//大写字母、小写字母、数字、特殊符号(不是字母,数字,下划线,汉字的字符)的8位以上组合
//手机号 第一位数字是1 第二位数字只能是3或4或5或6或7或8或9 剩下的九位数字可以是0-9之间任意一位数字
//邮箱判断
if ((usr.matches("^1[3-9]\\d{9}") || usr.matches("^(\\w+([-.][A-Za-z0-9]+)*){3,18}@\\w+([-.][A-Za-z0-9]+)*\\.\\w+([-.][A-Za-z0-9]+)*$"))
&& pw.matches("^(?![A-Za-z0-9]+$)(?![a-z0-9\\W]+$)(?![A-Za-z\\W]+$)(?![A-Z0-9\\W]+$)[a-zA-Z0-9\\W]{8,}$")) {
return "登录成功";
} else {
return "登录失败";
}
}
}
request库发送请求
这部分可参考接口测试基础那篇博客,最常用到get、post两种请求,传递参数类型有params、json、data,请求参数也可参考下面的这篇博客
CSDN
请求参类型params,json,data 含义理解_params和data、json传参的区别_默金……的博客-CSDN博客
这里举post接口传params的例子,(以开发文档为主,依赖于接口的定义)
import requests
class Login:
def login(self,usr,pw):
data = {"usr":usr,"pw":pw}
res = requests.post("http://localhost:8080/test/login",data=data) #也可以用params
return res.text
if __name__ == '__main__':
res = Login().login("18988888888","ABCabc012!@#")
print(res)
数据驱动
读取excle里的数据,用到xlrd库读取数据,并将字符串格式的参数转成json格式,用于传递参数
import xlrd
import json
def is_json(str_data):
try:
json.loads(str_data)
except ValueError:
return False
return True
class Argument:
def excel_control(self, tablePath, sheetName, caseName, *args):
workBook = xlrd.open_workbook(tablePath) # 打开表格
workSheet = workBook.sheet_by_name(sheetName) # 取第特定sheet页的表格
# 取列标 不确定要取哪列的数据 表头字段 对应的列标
index = []
for i in args:
index.append(workSheet.row_values(0).index(i))
case_index = 0
list_case = []
for one in workSheet.col_values(0): # 第一列数据遍历
if caseName in one: # 如果第一列中包含“login” 取出特定列
getdata = []
for num in index: # 要取出的第多少列的数据
res = workSheet.cell(case_index, num).value # 取出第多少行第多少列的数据
# 字典转为字符串
if is_json(res):
res = json.loads(res)
getdata.append(res)
list_case.append(getdata)
case_index += 1
return list_case
if __name__ == '__main__':
res = Argument().excel_control("../data/test_data.xls", "登录", "login", "请求参数")
Python与数据库的交互
在做接口自动化时,对返回结果进行断言时,需要对数据准确性进行判断,就需要用到查询数据库的操作,下面介绍两种数据库,主要涉及Python如何连接和操作数据库
Python+Mysql
mysql数据库是一种关系型数据库,表内表间具有一定的依赖关系,比如用户登录账号、用户的基本信息等一般存储在mysql数据库中
连接myslq,处理数据,可以从mysql中插入、取出数据
import pymysql
class GetUserInfo(object):
def query_mysql(self):
#连接数据库 ip 用户名 密码 数据库名
db = pymysql.connect(host='127.0.0.1',
user='root',
password='123456',
database='auto_test_data',
charset='utf8')
print("数据库连接成功!")
try:
#获得执行mysql命令的方法
cursor = db.cursor()
#sql查询语句
sql_query_usr = 'SELECT phone,email,pw FROM user WHERE usr = "test003"'
cursor.execute(sql_query_usr)#执行Mysql语句
user_info = cursor.fetchall()#接收全部的返回结果行
print(user_info)
print(type(user_info)) #查出的数据 存到一个元组里
except Exception:
print("查询失败")
db.close() #关闭数据库
if __name__ == '__main__':
usr_info = GetUserInfo().query_mysql()
Python+MongDB
MongDB数据库中可以包含多个文档,是一个集合的物理容器,相当于就是关系数据库中的表,以json格式存储数据
import pymongo
client = pymongo.MongoClient(host = 'localhost', port = 27017)
print(client.list_database_names())
#读取哪个数据库
db = client['my_test_data'] #也可以写成client.my_test_data
#读取哪个数据表
collection = db['test_data'] #也可以写成db.test_data
#查询集合下有多少个文档
print(collection.count_documents({}))
#筛选出'name'的值是'test002'的文档
print(collection.find_one({'name':'test002'}))
输出Allure报告
根据excel里的数据,传入参数,调用接口,最终会得到每一条case的结果,可以使用allure库, 展示出整个的完整接口自动化测试报告
import pytest, os, allure
from data_driven_tools.excel_control import Argument
from libs.login import Login
@allure.epic("Test") #史诗级 大的模块 对应allure报告的第一层
@allure.feature("登录模块") #功能点描述 XX模块 对应第二层
#类名必须以Test开头
class Test_login():
# 在xls表里取出传入的参数
@pytest.mark.parametrize("caseTitle,data,expdata",
Argument().excel_control("../data/test_data.xls", "登录", "login", "用例名称", "请求参数",
"返回结果"))
@allure.story("登录接口") #更为具体一层 具体场景 对应第三层
@allure.title("{caseTitle}") #对应每一条测试用例的名称 (在excel里维护)
#调用接口层 传入excel的参数
#方法名必须以test_开头
def test_login(self, caseTitle, data, expdata):
data = Login().login(data["usr"], data["pw"])
#进行断言
assert data == expdata
if __name__ == '__main__':
#pytest框架程序运行入口
pytest.main(['test_login.py', '-s', '--clean-alluredir','--alluredir','../report/tmp'])
#打开报告
os.system("allure serve ../report/tmp")
main()函数命令行里的参数使用介绍:
'test_login.py':执行的函数 如果为空,就运行当前项目下所有test_*.py或_test*.py这样的文件,
也可以进行指定运行的路径,例如:'../test_case/test_login.py',表示执行回到上层目录,进入test_case文件夹,执行test_login.py文件
执行py文件里指定的类,指定的方法,'../test_case/test_login.py::Test_login::test_login'
-k:可以使用and、or、not等逻辑运算符,区分匹配的范围,文件,类,函数名
-s:可以在控制台输出print信息(需要去掉-v参数)
-v:显示详细的用例执行信息,如下图所示:
-q:不输出用例执行的情况
-x:出现一条失败的测试用例就退出测试
--alluredir:清除上次执行的旧报告
--alluredir ../report/tmp:生成新报告,后面是新报告数据的生成路径
项目结构
整个项目结构是比较清晰的,分为接口层,数据驱动层,测试用例层
configs:可用来存放配置文件
data:excel:测试用例的数据
data_driven_tools:数据驱动工具,读取excel里的数据,传给接口
libs:使用request库调用接口
report:用于存放生成allure报告的原始数据,格式是json
test_case:存放测试用例,pytest框架执行程序的入口
requirements.txt文件,其他人配置环境需要添加的第三方库,可自动生成和下载
生成命令:pip freeze > requirements.txt
下载命令:pip install -r requirements.txt
总结
本篇博客总结了接口自动化项目的整个流程,用到了Pytest库、Allure库,xlrd读取excel里的测试用例,以及python操作数据库对数据准确性做验证,实现了接口自动化测试,对重要接口进行测试和数据验证,可用于冒烟测试,紧急发版前进行自动化测试,在企业落地后可以提升工作效率,节省手工测试的时间