1.接口测试框架的价值
1.效率
实现对所有测试脚本、测试数据文件以及测试报告文件的管理,提升接口测试执行和回归的效率
2.成本
降低人工的工作成本,可以通过框架自动来自动运行,提高人工的产能
3.复用
框架可以应对多种不同的接口测试工作的需求,适用性和扩展性强
4.规范
对接口测试成功物进行规范化管理,方便随时进行工作的开展以及成果物的查阅
2.框架设计思路
框架设计目标:最终只需要调整框架配置文件的一些参数,不需要人工干预测试脚本的执行
框架设计的过程:
1.框架的层次确定下来:
1.配置层:框架的配置文件---csv
2.脚本层:独立接口脚本,联调的接口脚本
3.数据层:独立接口数据,联调接口数据
4.报告层:联调接口测试报告,框架测试报告(此次框架执行过程中,运行了哪些接口测试脚本?)
2.对框架的设计进行评审
3.创建框架对应的文件夹(框架分层):
4.把现有相关的成果物,放入对应的文件夹,命名尽量有一个统一的规范:
脚本成果物(独立接口测试脚本,联调接口测试脚本)
测试数据文件
测试报告文件
框架配置文件
5.框架的设计
6.框架的实现
7.框架的调试运行
测试框架执行原理
Unittest测试框架设计原理
3.unittest框架使用原理及语法规则
案例演示V1.0(简单的框架脚本封装实现):通过unittest框架实现注册接口测试
2.设计:定义测试类,必须继承unittest类
class 测试类名(unittest.TestCase):
语法步骤:
1.导入unittest库
import unittest
2.定义测试类,必须继承unittest.TestCase
class RegisterTest(unittest.TestCase):
3.测试方法名字必须以test_开头
def test_register(self):
4.在main函数中直接使用unittest.main()即可
if __name__ == '__main__':
unittest.main()
5.加入断言:assert断言函数,响应结果是json格式需进行类型转换
self.assertIn("用户名已经存在", str(response))
6.通过使用setUp进行测试的初始化工作,如果多个测试方法用的都是同一套数据的话,就可以在一个setUp里写
def setUp(self):
self.url ="http:/xxxxxxxxxxx/user/register.do"
self.userinfo = {"username": "程勇1",
"password": "123456",
"email": "chengyong1@abcd.com",
"phone": "13825465786",
"question": "最喜欢的书",
"answer": "幸福人生"}
完整代码演示
# 定义测试类,继承unittest框架
import unittest
import requests
class RegisterTest(unittest.TestCase):
# 使用setUp方法完成接口测试的初始化工作
def setUp(self):
self.url = "http:/xxxxxxxxxxx/user/register.do"
self.userinfo = {"username": "程勇1",
"password": "123456",
"email": "chengyong1@abcd.com",
"phone": "13825465786",
"question": "最喜欢的书",
"answer": "幸福人生"}
# 定义unittest测试方法
def test_register(self):
# 发送接口请求
s = requests.session()
response = s.post(self.url, self.userinfo).json()
print(response)
# 把json格式的响应结果转换成字符串
# result = str(response)
# msg = result.find("用户名已经存在")
# if msg > 0:
# print("注册接口测试通过")
# else:
# print("注册接口测试失败")
# 现在使用unittest框架断言来进行结果判断
self.assertIn("用户名已经存在", str(response))
if __name__ == '__main__':
unittest.main()
案例演示V1.2(简单的框架脚本封装实现):通过unittest框架实现检查用户名或邮件是否有效接口测试
7.通过使用teardown进行测试的回收工作(setUp打开文件,teardown关闭文件)
完整代码演示:
# coding:utf8
# 实验二:针对检查接口通过unittest框架进行脚本实现
# 导入相关库文件
# 定义测试类,继承unittest框架
import csv
import unittest
import requests
class checktest(unittest.TestCase):
# 使用setUp进行接口测试初始化
def setUp(self):
self.file1 = open("../testdatafile/ind_interface/check_test_data.csv", "r")
self.file2 = open("../testresultfile/ind_interface/check_result.csv", "w")
self.url = "http://xxxxxxxxxx/user/check_vaild.do"
# 定义接口测试方法
def test_check(self):
# 从csv文件中读取测试数据
checkinfo = {}
table = csv.reader(self.file1)
for row in table:
checkinfo["str"] = row[0]
checkinfo["type"] = row[1]
print(row[0])
s = requests.session()
response = s.post(self.url, data=checkinfo).text
print(response)
# 原来是用if判断添加断言,现在用assert添加断言
self.assertIn(row[2], str(response))
# 通过teardown方法进行回收工作
def tearDown(self):
self.file1.close()
self.file2.close()
if __name__ == '__main__':
unittest.main()
案例演示V1.3(多个接口联调测试):通过unittest框架实现多个接口的联调测试------注册接口,登录接口
实现步骤:
1.导入unittest框架
2.定义测试类-----指定一个测试类实现多个测试方法
3.定义setUp进行初始化
4.定义test方法
5.使用测试套进行测试用例的执行
6.使用文件加载的方式进行测试用例的执行
思考:框架如何进行测试方法执行顺序控制?
1.如果框架中只有一个方法:先执行setUp,然后再执行测试方法test_xxx,最后才执行tearDown
2.如果框架中有多个方法:是按照asc码顺序执行的(方法名字母顺序a–z),执行顺序如下:
setUp
测试方法test_case1
tearDown
setUp
测试方法test_case2
tearDown
....
使用测试套进行测试用例的执行步骤:
1.在main里面声明测试套对象
suite = unittest.TestSuite()
2.把需要执行的测试用例用addTest方法加入测试套中
由addTest的顺序来进行测试方法执行顺序的控制
suite.addTest(测试类的名称("test_xxx"))
3.声明框架运行的对象
runner = unittest.TextTestRunner()
4.通过runner对象执行测试套件
runner.run(suite)
if __name__ == '__main__':
# 声明测试套对象
suite = unittest.TestSuite()
# 调用addTest方法调用类里面的方法就把类写再前面,再写入方法名
suite.addTest(mulinterfacetest("test_case2"))
suite.addTest(mulinterfacetest("test_case1"))
# 声明测试运行对象
runner = unittest.TextTestRunner()
runner.run(suite)
测试框架之unittest.main()运行原理:
在main里面执行测试方法无法控制执行顺序,所有的用例方法只要没有注释都是会全部执行
if __name__ 'main':
unittest.main()
测试框架之unittest.TestSuite()运行原理:
如果想指定执行某一个测试用例就用TestSuite测试套来执行
使用文件加载的方式进行测试用例的执行:
执行一些或一个python的测试文件
实现步骤:
1.声明文件路径
2.通过调用unittest对应的discower方法打开对应的测试文件
3.声明一个runner的对象
4.执行指定的测试文件
# 以文件的方式来进行测试框架的执行
# 声明文件所在路径
testdir = './' # 这里是路径
discower = unittest.defaultTestLoader.discover(testdir, pattern="test*.py")
# 声明测试运行对象
runner = unittest.TextTestRunner()
runner.run(discower)
小结:
unittest框架的使用要求:
1.导入
import unittest
2.定义测试类需要继承unittest
class 测试类名(unittest.TestCase)
unittest测试框架的基本组成要素
1.setUp初始化方法-------这个方法是可选的,可以有也可以没有,这个是测试前期的初始化工作
2.以test_打头的测试方法
3.tearDown方法资源回收------可选,一般用来关闭一些对象释放对象或者关闭一些文件
4.运行方式
unitest框架的执行顺序:
setUp进行初始化
执行测试方法
tearDown进行资源回收
三种不同的框架运行方式的对比:
unittest.main()好处: 特点:只能执行当前类中对应的所有测试方法
1.依次执行当前文件中对应测试类的所有测试方法
2.执行顺序以asc码顺序
3.一般的测试方法名称建议定义为:test_case1,test_case2…
测试套件的执行: 特点:按照加载顺序的顺序和个数进行执行
注意:运行模式要改为以python文件而不是测试框架模式运行
1.声明一个测试套
suite = unittest.TestSuite()
2.通过addTest方法添加测试用例------对应的测试方法
suite.addTest(类名("测试方法名"))
3.声明一个测试运行对象
runner = unittest.TextTestRunner()
4.执行测试套
runner.run(suite)
测试文件执行: 特点:执行任意指定路径下的任意相关命名的python测试脚本,执行每一个文件中所有的测试方法,顺序也是按照asc码顺序进行
1.声明文件所在路径
2.定义discower对象打开相关的脚本文件
discower = unittest.defaultTestloder.discower(文件路径,pattern=“test_*.py”)
3.声明测试运行对象
runner = unittest.TexttestRunner()
4.执行测试套
runner.run(discower)
3.自主研发测试框架
需求原型:
1.框架目录结构,一般的设计思路:配置层,脚本层,报告层,驱动层;这里的分层没有加入驱动层
2.框架各层需要完成的工作:
1.配置层:config,不同人设计的配置层相关内容是不一样的,这里设计的配置层里面的放的是csv文件,由配置文件来控制此次测试执行需要调用哪些测试脚本
2.脚本层:script, ind_interface:存放独立接口测试脚本,表示一个类中有一个测试方法,完成一个接口的测试;mul_interface:存放联调接口测试脚本,一个类中有多个测试方法,完成接口与联调的测试
注意:脚本文件的名称要有一定的规范性,此次规定测试脚本文件以test_开头
3.测试数据文件层:testdatafile,ind_interface:存放独立接口测试脚本对应的测试数据文件;mul_interface:存放的是联调接口测试脚本对应的测试数据文件
4.测试报告文件层:testresultfile,framresult:测试框架报告;ind_interface:存放独立接口测试报告;mul_interface:存放联调接口测试报告
5.框架驱动层:test_driver:存放测试框架的驱动程序
框架的测试执行过程:
先由框架驱动层中的框架驱动程序运行,依据配置层相关的设置调用对应的脚本层的程序进行执行,相关的脚本运行时,如果需要测试数据,则在数据层进行脚本文件的读取,测试脚本执行结束后,会写明相关的测试报告文件,并存入测试报告层
测试框架前期的准备工作:
1.依据框架需求搭建框架项目及模块
2.接口测试数据文件向框架转移
框架分层目录结构图:这里加入驱动层
框架测试脚本的研发:
1.重构测试脚本:案例演示:更新用户信息接口测试
实现步骤:
1.在框架对应的分层下创建新的python文件(注意:符合命名规范)
2.按照unittest框架的思想进行脚本设计
一般来讲不需要这么多版本同时存在,看实际需求,如果1.0够用就直接可以测试执行了,若感觉1.0不充分就注释掉或者是分成不同得测试方法,还是在一个文件里写;这里采用的是用不同的测试方法实现不同版本的测试
V1.0
1.导入unittest
2.定义一个类,继承unittest
3.传入固定的接口测试数据(一组)
4.assert进行判断
V2.0
4.是否需要测试数据文件
V3.0
5.加入测试报告文件
3.测试脚本的实现:V1.0
脚本演示
# coding:utf8
#*********************************************************************
# 对更新用户信息的接口进行测试,使用unittest框架技术
# 接口说明
# 接口访问地址:
# http://xxxxxxx/update_infomation.do
# 接口传入参数:
# 1.email 2.phone 3.question 4.answer
# 接口预期返回值
# 1.email已存在,请更换email再尝试更新 2.更新个人信息成功 3.更新个人信息失败"
#************************************************************************
# 脚本实现:
# 导入相关的库
# 定义测试类,继承unittest框架
import unittest
import requests
class updateuser_test(unittest.TestCase):
# V1.0版本,传入一组固定的接口测试数据,进行接口测试
def test_case1(self):
# 传入指定的接口测试数据
url = "http://xxxxxxx/user/update_information.do"
userinfo = {"email": "xiugaiyonghu@qq.com",
"phone": "13898768578",
"question": "最喜欢的书",
"answer": "十万个为什么"}
# 进行接口调用
response = requests.post(url, data=userinfo).text
print(response)
if __name__ == '__main__':
unittest.main()
运行结果
Ran 1 test in 0.032s
OK
{"status":1,"msg":"用户未登录"}
设计问题分析:测试更新用户的接口,需要先进行登录
测试场景1:未登录,进行更新,提示:用户未登录
测试场景2:先登录,再进行更新(遇到问题:发送了登录请求,在调用更新接口时还是提示“用户未登录“需要传入sessionID)
需要解决的问题:解决方案:
方案1(常用):在当前的测试类中,追加一个setUp方法,登录的测试脚本写入setUp方法中
方案2:在当前的测试类中,追加一个新得测试方法test_case1(完成登录的调用),把原来的更新测试方法名改为test_case2
方案3:在当前的测试类及测试方法中,前面追加一段代码,完成登录的调用
方案四:另外创建一个脚本文件,来实现登录,通过测试框架进行接口测试联调
脚本传入sessionID的解决办法:
先用接口测试工具看一下接口响应里的JSESSION字典,在登录测试方法里获取到,并转换成字典,再写上字典的key,作为更新用户的传参使用
V1.0完整脚本案例
# coding:gbk
#*********************************************************************
# 对更新用户信息的接口进行测试,使用unittest框架技术
# 接口说明
# 接口访问地址:
# http://localhost:8888/jwshoplogin/user/update_infomation.do
# 接口传入参数:
# 1.email 2.phone 3.question 4.answer
# 接口预期返回值
# 1.email已存在,请更换email再尝试更新 2.更新个人信息成功 3.更新个人信息失败"
#************************************************************************
# 脚本实现:
# 导入相关的库
# 定义测试类,继承unittest框架
import unittest
import requests
class updateuser_test(unittest.TestCase):
# 通过setUp方法实现登录接口的调用
def setUp(self):
url = "http://xxxxxxx/user/login.do"
userinfo = {"username": "张三1",
"password": "123456"}
response = requests.post(url, data=userinfo)
# print(response.text)
# 获取sessionID转成字典类型写上字典类型的key,并存入一个变量,作为更新用户的的传参
self.sessionID = dict(response.cookies)['JSESSIONID']
print(self.sessionID)
# V1.0版本,传入一组固定的接口测试数据,进行接口测试
def test_case2(self):
# 传入指定的接口测试数据
url = "http://xxxxxxx/user/update_information.do"
userinfo = {"email": "xiugaiyonghu@qq.com",
"phone": "132546677685",
"question": "最喜欢的书",
"answer": "西游记"}
# 获取登录的sessionID并传入请求方法中
session = {'JSESSIONID': self.sessionID}
print(session)
# 进行接口调用
response = requests.post(url, data=userinfo, cookies=session).text
print(response)
self.assertIn("更新个人信息成功", response)
if __name__ == '__main__':
unittest.main()
运行结果
98D0C3CCB24BA805139F3CE4802C9C02
{'JSESSIONID': '98D0C3CCB24BA805139F3CE4802C9C02'}
{"status":0,"msg":"更新个人信息成功","data":{"id":38,"
测试脚本实现:V2.0:
1.是否需要测试数据文件:对测试数据文件进行设计(测试用例的设计)
更新用户数据接口,测试数据分析:
1.1正常:四组数据:1.email,2.phone,3.answer,3.question;考虑只更新任意一个数据,还是更新多组数据,或是更新全部数据都可以
1.2异常:考虑:1.未登录,2.邮箱冲突,3.电话的长度不正确,4.问题为空,5.答案为空等等
测试数据文件
2.把测试数据文件中的内容传入脚本
案例代码演示
# v2.通过csv文件进行更新测试数据的读取
# python文件名update_v2_test.py
#*********************************************************************
# 对更新用户信息的接口进行测试,使用unittest框架技术
# 接口说明
# 接口访问地址:
# http://localhost:8888/jwshoplogin/user/update_infomation.do
# 接口传入参数:
# 1.email 2.phone 3.question 4.answer
# 接口预期返回值
# 1.email已存在,请更换email再尝试更新 2.更新个人信息成功 3.更新个人信息失败"
#************************************************************************
import csv
import os
import unittest
import requests
class Update_v2_test(unittest.TestCase):
# 通过setUp方法实现登录接口的调用
def setUp(self):
# 从测试数据文件中读取url和登录测试数据
path = os.getcwd()
# print(path)
# p1 = os.path.abspath(os.path.dirname(path)+os.path.sep+".")
# print(p1)
# 获取当前路径的上两级目录路径
p2 = os.path.abspath(os.path.dirname(path)+os.path.sep+"..")
# print(p2)
# 获取到的上两级目录路径加上csv测试数据所在路径
self.fpath = p2 + "\\test_data_file\\ind_interface\\updateuser_test_data.csv"
# print(fpath)
# self.file = open("../../test_data_file/ind_interface/updateuser_test_data.csv")
userinfo = {}
file1 = open(self.fpath, "r")
table = csv.reader(file1)
for row in table:
url = row[0]
userinfo[row[3]] = row[4]
userinfo[row[5]] = row[6]
print(userinfo)
# 只想打印第一行信息就用break退出循环
break
response = requests.post(url, data=userinfo)
self.sessionID = dict(response.cookies)["JSESSIONID"]
print(self.sessionID)
# V2.0版本,读取指定测试数据文件中对应的内容,进行接口测试
def test_case2(self):
# 打开对应的文件
file1 = open(self.fpath, "r")
# 如何从指定行开始进行读取
table = csv.reader(file1)
userinfo = {}
number = 0
for row in table:
number += 1
if number > 1:
url = row[0]
expresult = row[1]
j = int(row[2])
# 下标从2开始,j表示有几组数据的下标乘以两组数据加上初始值,最后的2表示步长
for i in range(3, j*2+2, 2):
userinfo[row[i]] = row[i+1]
print(userinfo)
# 获取登录的sessionID并传入请求方法中
session = {'JSESSIONID': self.sessionID}
print(session)
# 进行接口调用
response = requests.post(url, data=userinfo, cookies=session).text
print(response)
userinfo = {}
self.assertIn("更新个人信息成功", response)
if __name__ == '__main__':
unittest.main()
小结:
注意的事项:
1.文件位置的读取,获取当前路径首先导包import os
,然后写path = os.getcwd()
获取上一级路径p1 = os.path.abspath(os.path.dirname(path)+os.path.sep+".")
,获取前两级路径在这里插入代码片p2 = os.path.abspath(os.path.dirname(path)+os.path.sep+"..")
获取上一级后面写一个点,获取上两级写两个点
2.数据文件的设计:把固定的内容放在前面的列,把不定向的参数放在后面的列中,通过手工加入参数个数,方便进行循环读取,注意参数的正确性,先设计正确的数据,保证脚本测试通过,再设计错误的数据。
3.从指定的某一行开始读取内容number =0 for row in table:
追加number += 1
例如想从第四行读起,前三行都空转过去if num >4
num = 0
for row in table:
num += 1
if num > 4:
测试脚本实现3.0:
加入测试报告文件:生成HTML格式的测试报告
步骤:
1.下载HTMLTestRunner.py
下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html
2.拷贝到项目文件夹下
3.导入HTMLReport包
from HTNLTestRunner import HTMLTestRunner
4.生成测试报告的脚本
做好测试执行前的准备工作,指定要执行的测试用例
1.以wb(二进制写文件)模式打开测试报告文件
2.使用HTMLTestRunner方法创建HTML文件
3.执行测试
4.关闭文件
代码演示
# V3.0 创建HTML格式的测试报告文件
# python文件名updateuser_v3_test.py
#*********************************************************************
# 对更新用户信息的接口进行测试,使用unittest框架技术
# 接口说明
# 接口访问地址:
# http://localhost:8888/jwshoplogin/user/update_infomation.do
# 接口传入参数:
# 1.email 2.phone 3.question 4.answer
# 接口预期返回值
# 1.email已存在,请更换email再尝试更新 2.更新个人信息成功 3.更新个人信息失败"
#************************************************************************
import csv
import os
import unittest
import requests
from HTMLTestRunner import HTMLTestRunner
class Updateuser_v3_test(unittest.TestCase):
# 通过setUp方法实现登录接口的调用
def setUp(self):
# 从csv测试数据文件中读取url和登录测试数据
path = os.getcwd()
# 获取当前路径的上两级路径
p2 = os.path.abspath(os.path.dirname(path) + os.path.sep+"..")
# 上两级路径加上测试数据所在路径
self.fpath = p2 + "\\test_data_file\\ind_interface\\updateuser_test_data.csv"
userinfo = {}
file = open(self.fpath, "r")
table = csv.reader(file)
for row in table:
url = row[0]
userinfo[row[3]] = row[4]
userinfo[row[5]] = row[6]
print(userinfo)
# 只打印第一行登录的测试数据,这里用break退出循环
break
response = requests.post(url, data=userinfo)
# print(response)
# 获取sessionID转换成字典类型,写上字典的key并存在变量里作作为写一个接口的调用
self.sessionID = dict(response.cookies)["JSESSIONID"]
# print(sessionID)
def test_case(self):
file = open(self.fpath, "r")
table = csv.reader(file)
userinfo = {}
n = 0
for row in table:
if n > 0:
url = row[0]
# 各行数据组的和的下标
j = int(row[2])
# 下标从3开始,一组是两个数据乘以2加上开始的初始值,步长是2
for i in range(3, j*2+3, 2):
# i是字典大的key,i+1是字典的值
userinfo[row[i]] = row[i + 1]
# print(userinfo)
# 传入上一个接口的sessionID
session = {"JSESSIONID": self.sessionID}
# print(session)
response = requests.post(url, data=userinfo, cookies=session).text
print(response)
n += 1
if __name__ == '__main__':
# unittest.main()
path = os.getcwd()
p2 = os.path.abspath(os.path.dirname(path) + os.path.sep + "..")
# 加载测试套
suite = unittest.TestSuite()
suite.addTest(Updateuser_v3_test("test_case"))
# 定义测试报告文件
filename = p2 + r"\test_result_file\ind_interface\updateuser_test_report.html"
# 以wb(二进制写文件的方式)打开文件
file = open(filename, "wb")
# 调用HTML测试报告的报告生成测试报告
runner = HTMLTestRunner(stream=file, title="更新用户接口测试", description="接口测试报告")
runner.run(suite)
file.close()
运行结果
注意:这里测试脚本类文件里面写的测试套,运行的时候需要修改运行方式,给文件改个名字,要么再新建一个文件写main函数调用才可以执行测试套,要不然还是会再框架里面执行就不会生成测试报告
.<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
Time Elapsed: 0:00:00.284698
生成的测试报告
小结:
1.在main函数中生成html格式的测试报告
1.获取要写入测试报告文件对应位置的路径
2.给定具体的测试报告文件名
3.以wb(二进制写入)的方式打开文件
4.设置测试套,并添加要测试的方法
5.生成测试报
runner = HTMLTestRunner(stream=file, title="标题", description="描述")
6.调用runner对象执行测试套
runner.run(suite)
7.关闭测试报告文件
测试框架设计流程图
4.测试框架驱动程序设计
设计及实现框架驱动程序
V1.0在配置文件中写入一个测试文件进行执行:
1.设计一个配置文件:脚本名称,脚本所在路径
2.读取配置文件的内容
3.找到对应的脚本文件进行调用
# 测试框架驱动程序1.0版本,文件名runner_v1_test
# 只是从配置文件中读取一个脚本文件进行调用
import unittest
import csv
if __name__ == '__main__':
# 指定对应得脚本路径1.0版本;从csv文件中读取相关的路径和文件名
file = open(r"E:\workspace2\interfaceframe\config\config1.csv")
table = csv.reader(file)
num = 0
for row in table:
if num > 0:
testdir = row[0]
fname = row[1]
print(testdir, fname)
num += 1
# testdir = "E:\workspace2\interfaceframe\script\ind_interface"
discover = unittest.defaultTestLoader.discover(testdir, pattern=fname)
# 定义一个运行对象
runner = unittest.TextTestRunner()
runner.run(discover)
运行结果
"status":0,"msg":"更新个人信息成功"}
{"status":0,"msg":"更新个人信息成功"}
{"status":0,"msg":"更新个人信息成功"}
{"status":0,"msg":"更新个人信息成功"}
{"status":0,"msg":"更新个人信息成功"}
{"status":0,"msg":"更新个人信息成功"}
{"status":0,"msg":"更新个人信息成功"}
.
----------------------------------------------------------------------
Ran 1 test in 0.411s
OK
小结:
思路:由简到繁选择一种框架调用模式defaultloader方式,先用常量值进行脚本的调试,路径和脚本名称都是常量,再把常量值改为变量值,逐个替换不要全部替换,再把变量值改为从文件读取
发现问题,添加print语句进行分析;问题:路径不一致,级别关系发生了变化;解决问题,调整脚本中对应的路径级别
discover = unittest.defaultTestLoader.discover(路劲, pattern=脚本名称)
V2.0在配置文件中写入两个测试文件进行执行:
1.修改配置文件
2.进行脚本的修改
# 测试框架驱动程序1.0版本,文件名runner_v1_test
# 只是从配置文件中读取一个脚本文件进行调用
import unittest
import csv
if __name__ == '__main__':
# 指定对应得脚本路径1.0版本;从csv文件中读取相关的路径和文件名
file = open(r"E:\workspace2\interfaceframe\config\config1.csv")
table = csv.reader(file)
num = 0
for row in table:
if num > 0:
testdir = row[0]
fname = row[1]
print(testdir, fname)
# testdir = "E:\workspace2\interfaceframe\script\ind_interface"
discover = unittest.defaultTestLoader.discover(testdir, pattern=fname)
# 定义一个运行对象
runner = unittest.TextTestRunner()
runner.run(discover)
num += 1
运行结果
{'username': '李慧1', 'password': '123456'}
{"status":0,"msg":"更新个人信息成功","data"}
{"status":0,"msg":"更新个人信息成功","data"}
{"status":0,"msg":"更新个人信息成功","data"}
{"status":0,"msg":"更新个人信息成功","data"}
{"status":0,"msg":"更新个人信息成功","data"}
{"status":0,"msg":"更新个人信息成功","data"}
{"status":0,"msg":"更新个人信息成功","data":}
{'username': '李慧1', 'password': '123456'}
.
----------------------------------------------------------------------
Ran 1 test in 0.390s
OK
{'email': 'lihuixiugai1@qq.com'}
{'JSESSIONID': '9D27D9C5104EEECEF6D94D07DD7C2A57'}
{"status":0,"msg":"更新个人信息成功","data"}
{'phone': '13277777777'}
{'JSESSIONID': '9D27D9C5104EEECEF6D94D07DD7C2A57'}
{"status":0,"msg":"更新个人信息成功","data"}
{'question': '李慧1问题更新'}
{'JSESSIONID': '9D27D9C5104EEECEF6D94D07DD7C2A57'}
{"status":0,"msg":"更新个人信息成功","data"}
{'answer': '李慧1答案更新'}
{'JSESSIONID': '9D27D9C5104EEECEF6D94D07DD7C2A57'}
{"status":0,"msg":"更新个人信息成功","data"}
{'email': 'lihuixiugai2@qq.com', 'phone': '13277777776'}
{'JSESSIONID': '9D27D9C5104EEECEF6D94D07DD7C2A57'}
{"status":0,"msg":"更新个人信息成功","data"}
{'question': '李慧2问题更新', 'answer': '李慧2答案更新'}
{'JSESSIONID': '9D27D9C5104EEECEF6D94D07DD7C2A57'}
{"status":0,"msg":"更新个人信息成功","data"}
{'email': 'lihuixiugai3@qq.com', 'phone': '13277777778', 'question': '李慧3问题更新', 'answer': '李慧3答案更新'}
{'JSESSIONID': '9D27D9C5104EEECEF6D94D07DD7C2A57'}
.
----------------------------------------------------------------------
Ran 1 test in 0.416s
OK
V3.0在配置文件中针对不同的运行状态进行文件的执行:
1.升级改造配置文件---------加入一列状态列(状态表示0/1;RUN/ONRUN;NO/YES:运行和不运行)
2.脚本的调整--------加入条件判断
# 测试框架驱动程序1.0版本,文件名runner_v1_test
# 只是从配置文件中读取一个脚本文件进行调用
import unittest
import csv
if __name__ == '__main__':
# 指定对应得脚本路径1.0版本;从csv文件中读取相关的路径和文件名
file = open(r"E:\workspace2\interfaceframe\config\config1.csv")
table = csv.reader(file)
num = 0
for row in table:
if num > 0 and row[2] == "yes":
testdir = row[0]
fname = row[1]
print(testdir, fname)
# testdir = "E:\workspace2\interfaceframe\script\ind_interface"
discover = unittest.defaultTestLoader.discover(testdir, pattern=fname)
# 定义一个运行对象
runner = unittest.TextTestRunner()
runner.run(discover)
num += 1
运行结果
E:\workspace2\interfaceframe\script\ind_interface updateuser_v2_test.py
E:\workspace2\interfaceframe\test_data_file\ind_interface\updateuser_test_data.csv
{'username': '李慧1', 'password': '123456'}
{'email': 'lihuixiugai1@qq.com'}
{'JSESSIONID': 'A7284724F342B08EE928506687CB14A2'}
{"status":0,"msg":"更新个人信息成功","data"}
{'phone': '13277777777'}
{'JSESSIONID': 'A7284724F342B08EE928506687CB14A2'}
{"status":0,"msg":"更新个人信息成功","data":{"id":47,"username":"李慧1}
{'question': '李慧1问题更新'}
{'JSESSIONID': 'A7284724F342B08EE928506687CB14A2'}
{"status":0,"msg":"更新个人信息成功","data"}
{'answer': '李慧1答案更新'}
{'JSESSIONID': 'A7284724F342B08EE928506687CB14A2'}
{"status":0,"msg":"更新个人信息成功","data":{"id":47,"username":"李慧1}
{'email': 'lihuixiugai2@qq.com', 'phone': '13277777776'}
{'JSESSIONID': 'A7284724F342B08EE928506687CB14A2'}
{"status":0,"msg":"更新个人信息成功","data":{"id":47,"username":"李慧1}
{'question': '李慧2问题更新', 'answer': '李慧2答案更新'}
{'JSESSIONID': 'A7284724F342B08EE928506687CB14A2'}
{"status":0,"msg":"更新个人信息成功","data"}
{'email': 'lihuixiugai3@qq.com', 'phone': '13277777778', 'question': '李慧3问题更新', 'answer': '李慧3答案更新'}
{'JSESSIONID': 'A7284724F342B08EE928506687CB14A2'}
.
----------------------------------------------------------------------
Ran 1 test in 0.274s
OK
V4.0按照测试人员指定的顺序来执行相应的测试文件:
1.升级改造配置文件-----------加入执行顺序列
2.修改脚本
# v4.0完成从配置文件中读取测试脚本,执行状态以及执行顺序
# 文件名称 runner_v2_test
# 实验:对数据字典的内容进行排序
import operator
# dic = {"testA": 3, "testC": 1, "testB": 4, "testD": 2}
# dicn = sorted(dic.items(), key=operator.itemgetter(1))
# print(dicn)
# for fn in dicn:
# print(fn[1])
# 实验:把配置文件中的内容放入字典中
# import csv
# 以只读方式打开
# file = open(r"E:\workspace2\interfaceframe\config\config1.csv")
# tanle = csv.reader(file)
# # line = len(open(r"E:\workspace2\interfaceframe\config\config1.csv").readlines())
# # print(line)
# dic = {}
# listd = []
# line = 0
# for row in tanle:
# # print(row[0])
# if line > 0:
# dic = {}
# # 把文件中读取的数据放入字典
# dic[row[1]] = row[0]
# dic["num"] = int(row[3])
# # print(dic)
# line += 1
# if dic != {}:
# listd.append(dic)
# print("n,行数", line)
# # print(listd)
# dicn = sorted(listd, key=operator.itemgetter("num"))
# print(dicn)
# for i in range(0, line-1):
# n = 0
# for content in dicn[i].items():
# if n == 0:
# fname = print(content[0])
# fdir = print(content[1])
# print(fname, fdir)
# n += 1
#**********************V4.0驱动程序**************************************************
import unittest
import csv
import operator
if __name__ == '__main__':
# 打开对应的配置文件,进行读取
# 以只读方式打开
file = open(r"E:\workspace2\interfaceframe\config\config1.csv")
tanle = csv.reader(file)
# line = len(open(r"E:\workspace2\interfaceframe\config\config1.csv").readlines())
# print(line)
dic = {}
listd = []
line = 0
for row in tanle:
# print(row[0])
if line > 0:
dic = {}
# 把文件中读取的数据放入字典
dic[row[1]] = row[0]
dic["order"] = int(row[3])
# print(dic)
line += 1
if dic != {}:
listd.append(dic)
print("n,行数", line)
# print(listd)
dicn = sorted(listd, key=operator.itemgetter("order"))
print(dicn)
for i in range(0, line-1):
n = 0
for content in dicn[i].items():
if n == 0:
fname = (content[0])
fdir = (content[1])
print(fname, fdir)
# 调用脚本进行执行
discover = unittest.defaultTestLoader.discover(fdir, pattern=fname)
# 定义一个运行对象
runner = unittest.TextTestRunner()
runner.run(discover)
n += 1
V5.0按照测试顺序和是否运行来确定要执行哪些测试:
复杂的程序编写思路:
1.分解任务
2.逐步合并,分段调试
3.脚本设计思路:
突破点:python提供的数据字典的排序:
脚本名,脚本路路径、执行顺序,是相关的一组数据,不是无关的;import operator sorted(数据字典,key=operater.itemgetter(下标或标签))
实验一:给定一些字典的基本数据,排序算法是否可行
dic = {"testA": 3, "testC": 1, "testB": 4, "testD": 2}
dicn = sorted(dic.items(), key=operator.itemgetter(1))
print(dicn) -----排序算是否可行
实验二:把csv配置文件的一行内容导入字典中
实验三:把csv配置文件的多行内容导入到字典中
实验四:检验读取的顺序是否正确,能否正确执行
实验五:加入对状态的判断
# coding:utf8
# 把所有配置文件中的内容全部进行读取
# 文件名:runner_v3_test
import unittest
import csv
import operator
if __name__ == '__main__':
# 打开对应的配置文件,进行读取
# 以只读方式打开
file = open(r"E:\workspace2\interfaceframe\config\config1.csv", 'r')
table = csv.reader(file)
# line = len(open(r"E:\workspace2\interfaceframe\config\config1.csv").readlines())
# print(line)
dic = {}
listd = []
line = 0
for row in table:
# print(row[0])
if line > 0:
# 每一次执行之前清空字典
dic = {}
# 把文件中读取的数据放入字典
dic[row[1]] = row[0]
dic["order"] = int(row[3])
# 把脚本的运行状态加入字典数据
dic["stada"] = row[2]
# print(dic)
line += 1
if dic != {}:
listd.append(dic)
print("n,行数", line)
# print(listd)
dicn = sorted(listd, key=operator.itemgetter("order"))
# print(dicn)
# 从列表字典读取数据,for key,value in dict.items()
for i in range(0, line-1):
n = 0
for content in dicn[i].items():
if n == 0:
# print(content)
fname = (content[0])
fdir = (content[1])
# print("文件名", fname, "路径", fdir)
if n == 2:
# print(content)
state = content[1]
print("state", state)
if state == "yes":
# 调用脚本进行执行
print("最终运行的程序", fname)
discover = unittest.defaultTestLoader.discover(fdir, pattern=fname)
# 定义一个运行对象
runner = unittest.TextTestRunner()
runner.run(discover)
n += 1