Python+request+unittest實(shí)現(xiàn)接口測(cè)試框架集成實(shí)例
1、為什么要寫代碼實(shí)現(xiàn)接口自動(dòng)化
大家知道很多接口測(cè)試工具可以實(shí)現(xiàn)對(duì)接口的測(cè)試,如postman、jmeter、fiddler等等,而且使用方便,那么為什么還要寫代碼實(shí)現(xiàn)接口自動(dòng)化呢?工具雖然方便,但也不足之處:
測(cè)試數(shù)據(jù)不可控制
接口測(cè)試本質(zhì)是對(duì)數(shù)據(jù)的測(cè)試,調(diào)用接口,輸入一些數(shù)據(jù),隨后,接口返回一些數(shù)據(jù)。驗(yàn)證接口返回?cái)?shù)據(jù)的正確性。在用工具運(yùn)行測(cè)試用例之前不得不手動(dòng)向數(shù)據(jù)庫(kù)中插入測(cè)試數(shù)據(jù)。這樣我們的接口測(cè)試是不是就沒(méi)有那么“自動(dòng)化了”。
無(wú)法測(cè)試加密接口
這是接口測(cè)試工具的一大硬傷,如我們前面開發(fā)的接口用工具測(cè)試完全沒(méi)有問(wèn)題,但遇到需要對(duì)接口參 數(shù)進(jìn)行加密/解密的接口,例如 md5、base64、AES 等常見加密方式。本書第十一章會(huì)對(duì)加密接口進(jìn)行介紹。 又或者接口的參數(shù)需要使用時(shí)間戳,也是工具很難模擬的。
擴(kuò)展能力不足
當(dāng)我們?cè)谙硎芄ぞ咚鶐?lái)的便利的同時(shí),往往也會(huì)受制于工具所帶來(lái)的局限。例如,我想將測(cè)試結(jié)果生 成 HMTL 格式測(cè)試報(bào)告,我想將測(cè)試報(bào)告發(fā)送到指定郵箱。我想對(duì)接口測(cè)試做定時(shí)任務(wù)。我想對(duì)接口測(cè)試做持續(xù)集成。這些需求都是工具難以實(shí)現(xiàn)的。
2、接口自動(dòng)化測(cè)試設(shè)計(jì)
接口測(cè)試調(diào)用過(guò)程可以用下圖概括,增加了測(cè)試數(shù)據(jù)庫(kù)
一般的 接口工具 測(cè)試過(guò)程:
1、接口工具調(diào)用被測(cè)系統(tǒng)的接口(傳參 username="zhangsan")。
2、系統(tǒng)接口根據(jù)傳參(username="zhangsan")向 正式數(shù)據(jù)庫(kù) 中查詢數(shù)據(jù)。
3、將查詢結(jié)果組裝成一定格式的數(shù)據(jù),并返回給被調(diào)用者。
4、人工或通過(guò)工具的斷言功能檢查接口測(cè)試的正確性。
接口自動(dòng)化測(cè)試項(xiàng)目,為了使接口測(cè)試對(duì)數(shù)據(jù)變得可控,測(cè)試過(guò)程如下:
1、接口測(cè)試項(xiàng)目先向 測(cè)試數(shù)據(jù)庫(kù) 中插入測(cè)試數(shù)據(jù)(zhangsan 的個(gè)人信息)。
2、調(diào)用被測(cè)系統(tǒng)接口(傳參 username="zhangsan")。
3、系統(tǒng)接口根據(jù)傳參(username="zhangsan")向測(cè)試數(shù)據(jù)庫(kù)中進(jìn)行查詢并得到 zhangsan 個(gè)人信息。
4、將查詢結(jié)果組裝成一定格式的數(shù)據(jù),并返回給被調(diào)用者。
5、通過(guò)單元測(cè)試框架斷言接口返回的數(shù)據(jù)(zhangsan 的個(gè)人信息),并生成測(cè)試報(bào)告。
為了使正式數(shù)據(jù)庫(kù)的數(shù)據(jù)不被污染,建議使用獨(dú)立的 測(cè)試數(shù)據(jù)庫(kù) 。
2、requests庫(kù)
Requests 使用的是 urllib3,因此繼承了它的所有特性。Requests 支持 HTTP 連接保持和連接池 ,支持 使用cookie保持會(huì)話 ,支持 文件上傳 ,支持 自動(dòng)確定響應(yīng)內(nèi)容的編碼。 對(duì)request庫(kù)的更詳細(xì)的介紹可以看我之前接口測(cè)試基礎(chǔ)的文章:
http://m.fzitv.net/article/122571.htm?pc
http://m.fzitv.net/article/108168.htm
3、接口測(cè)試代碼示例
下面以之前用 python+django 開發(fā)的用戶簽到系統(tǒng)為背景,展示接口測(cè)試的代碼。
為什么開發(fā)接口?開發(fā)的接口主要給誰(shuí)來(lái)用?
前端和后端分離是近年來(lái) Web 應(yīng)用開發(fā)的一個(gè)發(fā)展趨勢(shì)。這種模式將帶來(lái)以下優(yōu)勢(shì):
1、后端可以不用必須精通前端技術(shù)(HTML/JavaScript/CSS),只專注于數(shù)據(jù)的處理,對(duì)外提供 API 接口。
2、前端的專業(yè)性越來(lái)越高,通過(guò) API 接口獲取數(shù)據(jù),從而專注于頁(yè)面的設(shè)計(jì)。
3、前后端分離增加接口的應(yīng)用范圍,開發(fā)的接口可以應(yīng)用到 Web 頁(yè)面上,也可以應(yīng)用到移動(dòng) APP 上。
在這種開發(fā)模式下,接口測(cè)試工作就會(huì)變得尤為重要了。
開發(fā)實(shí)現(xiàn)的接口代碼示例:
# 添加發(fā)布會(huì)接口實(shí)現(xiàn)
def add_event(request):
eid = request.POST.get('eid','') # 發(fā)布會(huì)id
name = request.POST.get('name','') # 發(fā)布會(huì)標(biāo)題
limit = request.POST.get('limit','') # 限制人數(shù)
status = request.POST.get('status','') # 狀態(tài)
address = request.POST.get('address','') # 地址
start_time = request.POST.get('start_time','') # 發(fā)布會(huì)時(shí)間
if eid =='' or name == '' or limit == '' or address == '' or start_time == '':
return JsonResponse({'status':10021,'message':'parameter error'})
result = Event.objects.filter(id=eid)
if result:
return JsonResponse({'status':10022,'message':'event id already exists'})
result = Event.objects.filter(name=name)
if result:
return JsonResponse({'status':10023,'message':'event name already exists'})
if status == '':
status = 1
try:
Event.objects.create(id=eid,name=name,limit=limit,address=address,status=int(status),start_time=start_time)
except ValidationError:
error = 'start_time format error. It must be in YYYY-MM-DD HH:MM:SS format.'
return JsonResponse({'status':10024,'message':error})
return JsonResponse({'status':200,'message':'add event success'})
通過(guò)POST請(qǐng)求接收發(fā)布會(huì)參數(shù):發(fā)布會(huì)id、標(biāo)題、人數(shù)、狀態(tài)、地址和時(shí)間等參數(shù)。
首先,判斷eid、name、limit、address、start_time等字段均不能為空,否則JsonResponse()返回相應(yīng)的狀態(tài)碼和提示。JsonResponse()是一個(gè)非常有用的方法,它可以直接將字典轉(zhuǎn)化成Json格式返回到客戶端。
接下來(lái),判斷發(fā)布會(huì)id是否存在,以及發(fā)布會(huì)名稱(name)是否存在;如果存在將返回相應(yīng)的狀態(tài)碼和 提示信息。
再接下來(lái),判斷發(fā)布會(huì)狀態(tài)是否為空,如果為空,將狀態(tài)設(shè)置為1(True)。
最后,將數(shù)據(jù)插入到 Event 表,在插入的過(guò)程中如果日期格式錯(cuò)誤,將拋出 ValidationError 異常,接收 該異常并返回相應(yīng)的狀態(tài)和提示,否則,插入成功,返回狀態(tài)碼200和“add event success”的提示。
# 發(fā)布會(huì)查詢接口實(shí)現(xiàn)
def get_event_list(request):
eid = request.GET.get("eid", "") # 發(fā)布會(huì)id
name = request.GET.get("name", "") # 發(fā)布會(huì)名稱
if eid == '' and name == '':
return JsonResponse({'status':10021,'message':'parameter error'})
if eid != '':
event = {}
try:
result = Event.objects.get(id=eid)
except ObjectDoesNotExist:
return JsonResponse({'status':10022, 'message':'query result is empty'})
else:
event['eid'] = result.id
event['name'] = result.name
event['limit'] = result.limit
event['status'] = result.status
event['address'] = result.address
event['start_time'] = result.start_time
return JsonResponse({'status':200, 'message':'success', 'data':event})
if name != '':
datas = []
results = Event.objects.filter(name__contains=name)
if results:
for r in results:
event = {}
event['eid'] = r.id
event['name'] = r.name
event['limit'] = r.limit
event['status'] = r.status
event['address'] = r.address
event['start_time'] = r.start_time
datas.append(event)
return JsonResponse({'status':200, 'message':'success', 'data':datas})
else:
return JsonResponse({'status':10022, 'message':'query result is empty'})
通過(guò)GET請(qǐng)求接收發(fā)布會(huì)id和name 參數(shù)。兩個(gè)參數(shù)都是可選的。首先,判斷當(dāng)兩個(gè)參數(shù)同時(shí)為空,接口返回狀態(tài)碼10021,參數(shù)錯(cuò)誤。
如果發(fā)布會(huì)id不為空,優(yōu)先通過(guò)id查詢,因?yàn)閕d的唯一性,所以,查詢結(jié)果只會(huì)有一條,將查詢結(jié)果 以 key:value 對(duì)的方式存放到定義的event字典中,并將數(shù)據(jù)字典作為整個(gè)返回字典中data對(duì)應(yīng)的值返回。
name查詢?yōu)槟:樵?,查詢?shù)據(jù)可能會(huì)有多條,返回的數(shù)據(jù)稍顯復(fù)雜;首先將查詢的每一條數(shù)據(jù)放到一 個(gè)字典event中,再把每一個(gè)字典再放到數(shù)組datas中,最后再將整個(gè)數(shù)組做為返回字典中data對(duì)應(yīng)的值返回。
接口測(cè)試代碼示例
#查詢發(fā)布會(huì)接口測(cè)試代碼
import requests
url = "http://127.0.0.1:8000/api/get_event_list/"
r = requests.get(url, params={'eid':'1'})
result = r.json()
print(result)
assert result['status'] == 200
assert result['message'] == "success"
assert result['data']['name'] == "xx 產(chǎn)品發(fā)布會(huì)"
assert result['data']['address'] == "北京林匹克公園水立方"
assert result['data']['start_time'] == "2016-10-15T18:00:00"
因?yàn)椤鞍l(fā)布會(huì)查詢接口”是GET類型,所以,通過(guò)requests庫(kù)的get()方法調(diào)用,第一個(gè)參數(shù)為調(diào)用接口的URL地址,params設(shè)置接口的參數(shù),參數(shù)以字典形式組織。
json()方法可以將接口返回的json格式的數(shù)據(jù)轉(zhuǎn)化為字典。
接下來(lái)就是通過(guò) assert 語(yǔ)句對(duì)接字典中的數(shù)據(jù)進(jìn)行斷言。分別斷言status、message 和data的相關(guān)數(shù)據(jù)等。
使用unittest單元測(cè)試框架開發(fā)接口測(cè)試用例
#發(fā)布會(huì)查詢接口測(cè)試代碼
import unittest
import requests
class GetEventListTest(unittest.TestCase):
def setUp(self):
self.base_url = "http://127.0.0.1:8000/api/get_event_list/"
def test_get_event_list_eid_null(self):
''' eid 參數(shù)為空 '''
r = requests.get(self.base_url, params={'eid':''})
result = r.json()
self.assertEqual(result['status'], 10021)
self.assertEqual(result['message'], 'parameter error')
def test_get_event_list_eid_error(self):
''' eid=901 查詢結(jié)果為空 '''
r = requests.get(self.base_url, params={'eid':901})
result = r.json()
self.assertEqual(result['status'], 10022)
self.assertEqual(result['message'], 'query result is empty')
def test_get_event_list_eid_success(self):
''' 根據(jù) eid 查詢結(jié)果成功 '''
r = requests.get(self.base_url, params={'eid':1})
result = r.json()
self.assertEqual(result['status'], 200)
self.assertEqual(result['message'], 'success')
self.assertEqual(result['data']['name'],u'mx6發(fā)布會(huì)')
self.assertEqual(result['data']['address'],u'北京國(guó)家會(huì)議中心')
def test_get_event_list_nam_result_null(self):
''' 關(guān)鍵字‘a(chǎn)bc'查詢 '''
r = requests.get(self.base_url, params={'name':'abc'})
result = r.json()
self.assertEqual(result['status'], 10022)
self.assertEqual(result['message'], 'query result is empty')
def test_get_event_list_name_find(self):
''' 關(guān)鍵字‘發(fā)布會(huì)'模糊查詢 '''
r = requests.get(self.base_url, params={'name':'發(fā)布會(huì)'})
result = r.json()
self.assertEqual(result['status'], 200)
self.assertEqual(result['message'], 'success')
self.assertEqual(result['data'][0]['name'],u'mx6發(fā)布會(huì)')
self.assertEqual(result['data'][0]['address'],u'北京國(guó)家會(huì)議中心')
49if __name__ == '__main__':
unittest.main()
unittest單元測(cè)試框架可以幫助 組織和運(yùn)行接口測(cè)試用例。
4、接口自動(dòng)化測(cè)試框架實(shí)現(xiàn)
關(guān)于接口自動(dòng)化測(cè)試,unittest 已經(jīng)幫我們做了大部分工作,接下來(lái)只需要 集成數(shù)據(jù)庫(kù)操作 ,以及 HTMLTestRunner測(cè)試報(bào)告生成 擴(kuò)展即可。
框架結(jié)構(gòu)如下圖:

pyrequests 框架:
db_fixture/: 初始化接口測(cè)試數(shù)據(jù)。
interface/: 用于編寫接口自動(dòng)化測(cè)試用例。
report/: 生成接口自動(dòng)化測(cè)試報(bào)告。
db_config.ini : 數(shù)據(jù)庫(kù)配置文件。
HTMLTestRunner.py unittest 單元測(cè)試框架擴(kuò)展,生成 HTML 格式的測(cè)試報(bào)告。
run_tests.py : 執(zhí)行所有接口測(cè)試用例。
4.1、數(shù)據(jù)庫(kù)配置
首先,需要修改被測(cè)系統(tǒng)將數(shù)據(jù)庫(kù)指向測(cè)試數(shù)據(jù)庫(kù)。以 MySQL數(shù)據(jù)庫(kù)為例,針對(duì) django 項(xiàng)目而言,修改.../guest/settings.py 文件??梢栽谙到y(tǒng)測(cè)試環(huán)境單獨(dú)創(chuàng)建一個(gè)測(cè)試庫(kù)。 這樣做的目的是讓接口測(cè)試的數(shù)據(jù)不會(huì)清空或污染到功能測(cè)試庫(kù)的數(shù)據(jù)。 其他框架開發(fā)的項(xiàng)目與django項(xiàng)目類似,這個(gè)工作一般由開發(fā)同學(xué)完成,我們測(cè)試同學(xué)更多關(guān)注的是測(cè)試框架的代碼。
4.2、框架代碼實(shí)現(xiàn)
4.2.1、首先,創(chuàng) 建數(shù)據(jù)庫(kù)配置文件.../db_config.ini

4.2.2、接下來(lái), 簡(jiǎn)單封裝數(shù)據(jù)庫(kù)操作,數(shù)據(jù)庫(kù)表數(shù)據(jù)的插入和清除 ,.../db_fixture/ mysql_db.py
import pymysql.cursors
import os
import configparser as cparser
# ======== Reading db_config.ini setting ===========
base_dir = str(os.path.dirname(os.path.dirname(__file__)))
base_dir = base_dir.replace('\\', '/')
file_path = base_dir + "/db_config.ini"
cf = cparser.ConfigParser()
cf.read(file_path)
host = cf.get("mysqlconf", "host")
port = cf.get("mysqlconf", "port")
db = cf.get("mysqlconf", "db_name")
user = cf.get("mysqlconf", "user")
password = cf.get("mysqlconf", "password")
# ======== MySql base operating ===================
class DB:
def __init__(self):
try:
# Connect to the database
self.connection = pymysql.connect(host=host,
port=int(port),
user=user,
password=password,
db=db,
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor)
except pymysql.err.OperationalError as e:
print("Mysql Error %d: %s" % (e.args[0], e.args[1]))
# clear table data
def clear(self, table_name):
# real_sql = "truncate table " + table_name + ";"
real_sql = "delete from " + table_name + ";"
with self.connection.cursor() as cursor:
cursor.execute("SET FOREIGN_KEY_CHECKS=0;")
cursor.execute(real_sql)
self.connection.commit()
# insert sql statement
def insert(self, table_name, table_data):
for key in table_data:
table_data[key] = "'"+str(table_data[key])+"'"
key = ','.join(table_data.keys())
value = ','.join(table_data.values())
real_sql = "INSERT INTO " + table_name + " (" + key + ") VALUES (" + value + ")"
#print(real_sql)
with self.connection.cursor() as cursor:
cursor.execute(real_sql)
self.connection.commit()
# close database
def close(self):
self.connection.close()
# init data
def init_data(self, datas):
for table, data in datas.items():
self.clear(table)
for d in data:
self.insert(table, d)
self.close()
if __name__ == '__main__':
db = DB()
table_name = "sign_event"
data = {'id':1,'name':'紅米','`limit`':2000,'status':1,'address':'北京會(huì)展中心','start_time':'2016-08-20 00:25:42'}
table_name2 = "sign_guest"
data2 = {'realname':'alen','phone':12312341234,'email':'alen@mail.com','sign':0,'event_id':1}
db.clear(table_name)
db.insert(table_name, data)
db.close()
首先,讀取 db_config.ini 配置文件。 創(chuàng)建 DB 類,__init__()方法初始化,通過(guò) pymysql.connect()連接數(shù)據(jù)庫(kù)。
因?yàn)檫@里只用到數(shù)據(jù)庫(kù)表的清除和插入,所以只創(chuàng)建 clear()和 insert()兩個(gè)方法。其中,insert()方法對(duì)數(shù) 據(jù)的插入做了簡(jiǎn)單的格式轉(zhuǎn)化,可將字典轉(zhuǎn)化成 SQL 插入語(yǔ)句,這樣格式轉(zhuǎn)化了方便了數(shù)據(jù)庫(kù)表數(shù)據(jù)的創(chuàng)建。
最后,通過(guò) close()方法用于關(guān)閉數(shù)據(jù)庫(kù)連接。
4.2.3、接下來(lái)接下來(lái) 創(chuàng)建測(cè)試數(shù)據(jù) ,.../db_fixture/ test_data.py
import sys
sys.path.append('../db_fixture')
try:
from mysql_db import DB
except ImportError:
from .mysql_db import DB
# create data
datas = {
'sign_event':[
{'id':1,'name':'紅米Pro發(fā)布會(huì)','`limit`':2000,'status':1,'address':'北京會(huì)展中心','start_time':'2017-08-20 14:00:00'},
{'id':2,'name':'可參加人數(shù)為0','`limit`':0,'status':1,'address':'北京會(huì)展中心','start_time':'2017-08-20 14:00:00'},
{'id':3,'name':'當(dāng)前狀態(tài)為0關(guān)閉','`limit`':2000,'status':0,'address':'北京會(huì)展中心','start_time':'2017-08-20 14:00:00'},
{'id':4,'name':'發(fā)布會(huì)已結(jié)束','`limit`':2000,'status':1,'address':'北京會(huì)展中心','start_time':'2001-08-20 14:00:00'},
{'id':5,'name':'小米5發(fā)布會(huì)','`limit`':2000,'status':1,'address':'北京國(guó)家會(huì)議中心','start_time':'2017-08-20 14:00:00'},
],
'sign_guest':[
{'id':1,'realname':'alen','phone':13511001100,'email':'alen@mail.com','sign':0,'event_id':1},
{'id':2,'realname':'has sign','phone':13511001101,'email':'sign@mail.com','sign':1,'event_id':1},
{'id':3,'realname':'tom','phone':13511001102,'email':'tom@mail.com','sign':0,'event_id':5},
],
}
# Inster table datas
def init_data():
DB().init_data(datas)
if __name__ == '__main__':
init_data()
init_data()函數(shù)用于讀取 datas 字典中的數(shù)據(jù),調(diào)用 DB 類中的 clear()方法清除數(shù)據(jù)庫(kù),然后,調(diào)用 insert() 方法插入表數(shù)據(jù)。
4.2.4、編寫 接口測(cè)試用例 。創(chuàng)建添加發(fā)布會(huì)接口測(cè)試文件.../interface/ add_event_test.py
import unittest
import requests
import os, sys
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, parentdir)
from db_fixture import test_data
class AddEventTest(unittest.TestCase):
''' 添加發(fā)布會(huì) '''
def setUp(self):
self.base_url = "http://127.0.0.1:8000/api/add_event/"
def tearDown(self):
print(self.result)
def test_add_event_all_null(self):
''' 所有參數(shù)為空 '''
payload = {'eid':'','':'','limit':'','address':"",'start_time':''}
r = requests.post(self.base_url, data=payload)
self.result = r.json()
self.assertEqual(self.result['status'], 10021)
self.assertEqual(self.result['message'], 'parameter error')
def test_add_event_eid_exist(self):
''' id已經(jīng)存在 '''
payload = {'eid':1,'name':'一加4發(fā)布會(huì)','limit':2000,'address':"深圳寶體",'start_time':'2017'}
r = requests.post(self.base_url, data=payload)
self.result = r.json()
self.assertEqual(self.result['status'], 10022)
self.assertEqual(self.result['message'], 'event id already exists')
def test_add_event_name_exist(self):
''' 名稱已經(jīng)存在 '''
payload = {'eid':11,'name':'紅米Pro發(fā)布會(huì)','limit':2000,'address':"深圳寶體",'start_time':'2017'}
r = requests.post(self.base_url,data=payload)
self.result = r.json()
self.assertEqual(self.result['status'], 10023)
self.assertEqual(self.result['message'], 'event name already exists')
def test_add_event_data_type_error(self):
''' 日期格式錯(cuò)誤 '''
payload = {'eid':11,'name':'一加4手機(jī)發(fā)布會(huì)','limit':2000,'address':"深圳寶體",'start_time':'2017'}
r = requests.post(self.base_url,data=payload)
self.result = r.json()
self.assertEqual(self.result['status'], 10024)
self.assertIn('start_time format error.', self.result['message'])
def test_add_event_success(self):
''' 添加成功 '''
payload = {'eid':11,'name':'一加4手機(jī)發(fā)布會(huì)','limit':2000,'address':"深圳寶體",'start_time':'2017-05-10 12:00:00'}
r = requests.post(self.base_url,data=payload)
self.result = r.json()
self.assertEqual(self.result['status'], 200)
self.assertEqual(self.result['message'], 'add event success')
if __name__ == '__main__':
test_data.init_data() # 初始化接口測(cè)試數(shù)據(jù)
unittest.main()
在測(cè)試接口之前,調(diào)用test_data.py文件中的init_data()方法初始化數(shù)據(jù)庫(kù)中的測(cè)試數(shù)據(jù)。
創(chuàng)建AddEventTest測(cè)試類繼承 unittest.TestCase 類,通過(guò)創(chuàng)建測(cè)試用例,調(diào)用相關(guān)接口,并驗(yàn)證接口返回 的數(shù)據(jù)。
4.2.5、創(chuàng)建 run_tests.py 文件
當(dāng)開發(fā)的接口達(dá)到一定數(shù)量后,就需要考慮 分文件分目錄 的來(lái) 劃分 接口測(cè)試用例,如何批量的執(zhí)行不同文件目錄下的用例呢?unittest單元測(cè)試框架提供的 discover() 方法可以幫助我們做到這一點(diǎn)。并使用 HTMLTestRunner 擴(kuò)展生成 HTML 格式的測(cè)試報(bào)告。
import time, sys
sys.path.append('./interface')
sys.path.append('./db_fixture')
from HTMLTestRunner import HTMLTestRunner
import unittest
from db_fixture import test_data
# 指定測(cè)試用例為當(dāng)前文件夾下的 interface 目錄
test_dir = './interface'
discover = unittest.defaultTestLoader.discover(test_dir, pattern='*_test.py')
if __name__ == "__main__":
test_data.init_data() # 初始化接口測(cè)試數(shù)據(jù)
now = time.strftime("%Y-%m-%d %H_%M_%S")
filename = './report/' + now + '_result.html'
fp = open(filename, 'wb')
runner = HTMLTestRunner(stream=fp,
title='Guest Manage System Interface Test Report',
description='Implementation Example with: ')
runner.run(discover)
fp.close()
首先,通過(guò)調(diào)用test_data.py文件中的init_data()函數(shù)來(lái)初始化接口測(cè)試數(shù)據(jù)。
使用unittest框架所提供的discover()方法,查找 interface/ 目錄下,所有匹配*_test.py 的測(cè)試文件(*星 號(hào)匹配任意字符)。
HTMLTestRunner 為unittest單元測(cè)試框架的擴(kuò)展,利用它所提供的HTMLTestRunner()類來(lái)替換unittest單元測(cè)試框架的TextTestRunner()類,從而生成HTML格式的測(cè)試報(bào)告。
遺憾的是HTMLTestRunner并不支持Python3.x,大家可以在網(wǎng)上找到適用于Python3.x的HTMLTestRunner.py文件,使用在自己的接口自動(dòng)化工程中。
通過(guò) time 的 strftime()方法獲取當(dāng)前時(shí)間,并且轉(zhuǎn)化成一定的時(shí)間格式。作為測(cè)試報(bào)告的名稱。這樣做目的是是為了避免因?yàn)樯傻膱?bào)告的名稱重名而造成報(bào)告的覆蓋。最終,將測(cè)試報(bào)告存放于report/目錄下面。如下圖,一張完整的接口自動(dòng)化測(cè)試報(bào)告。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python shell命令行中import多層目錄下的模塊操作
這篇文章主要介紹了python shell命令行中import多層目錄下的模塊操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Python二維數(shù)組不同初始化方式的差異說(shuō)明
這篇文章主要介紹了Python二維數(shù)組不同初始化方式的差異說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
Python讀取配置文件-ConfigParser的二次封裝方法
這篇文章主要介紹了Python讀取配置文件-ConfigParser的二次封裝方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
python運(yùn)行cmd命令10種方式并獲得返回值的高級(jí)技巧
這篇文章主要給大家介紹了關(guān)于python運(yùn)行cmd命令10種方式并獲得返回值的高級(jí)技巧,主要包括python腳本執(zhí)行CMD命令并返回結(jié)果的例子使用實(shí)例、應(yīng)用技巧,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03
用python實(shí)現(xiàn)學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了用python實(shí)現(xiàn)學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-07-07

