再次強(qiáng)調(diào),因為視頻中實戰(zhàn)地址已無法訪問,建議大家根據(jù)原理,用自己公司的業(yè)務(wù)邏輯、代碼來練手。本人公司使用pyhon2.7,所以語法可能與3.x不同
目標(biāo)
- 復(fù)習(xí)單元測試:引入單元測試、html測試報告、斷言結(jié)果
- 引入超繼承(二選一)
- 引入ddt(二選一)
- 添加一個字段存入測試結(jié)果
- 引入try...except...finally
- 完成用例的可配置化,想跑哪條用例,通過配置文件配置好
- 難點(diǎn):
- 同時跑多個模塊怎么跑
復(fù)習(xí)單元測試
使用unittest,測試我們自己封裝的http請求類-HttpRequest,目的一:學(xué)習(xí)如何進(jìn)行單元測試,目的二:寫出咱們的各個接口。
-
新建
test_http_request.py
編寫測試用例import json import unittest from common.public.http_request import HttpRequest class TestHttpRequest(unittest.TestCase): def setUp(self): pass def tearDown(self): pass #登錄接口 def test_login(self): payload = {"user_phone": "1801923****", "device_model": "iphone7"} res=HttpRequest().http_request("1.6.0", "android", "785c6fee0e4488ca412a5afc9a00e9d8","/login","post",payload) self.assertEqual(200,res.status_code) #添加斷言 print ("獲得的結(jié)果是:",res.json())
-
在
run.py
文件中加載用例、執(zhí)行用例import unittest from common.public.test_http_request import TestHttpRequest suite=unittest.TestSuite() suite.addTest(TestHttpRequest("test_login")) #添加用例 #執(zhí)行用例 runner=unittest.TextTestRunner() runner.run(suite)
-
使用HTMLTestRunner生成HTML測試報告
下載地址:http://tungwaiyip.info/software/HTMLTestRunner.html
使用:
- HTMLTestRunner是Python標(biāo)準(zhǔn)庫的unittest模塊的擴(kuò)展,無法通過pip安裝 - 下載HTMLTestRunner.py放在lib目錄下 - 導(dǎo)入模塊 `import HTMLTestRunner`
注意點(diǎn):
使用python2.x可以直接使用,python3.x需要進(jìn)行改造。
代碼改造為使用HTMLTestRunner生成HTML測試報告:
# encoding:utf-8 import sys reload(sys) sys.setdefaultencoding('utf8') #python2.7需要添加,否則會因編碼問題報錯 import HTMLTestRunner import unittest from common.public.test_http_request import TestHttpRequest suite=unittest.TestSuite() suite.addTest(TestHttpRequest("test_login")) #添加用例 with open("test_result/rusult.html","wb") as file: #執(zhí)行用例 runner=HTMLTestRunner.HTMLTestRunner(stream=file,verbosity=2,title="測試HttpRequest類") runner.run(suite)
獲得的html格式的測試報告:
image
引入ddt
引入ddt的目的是為了數(shù)據(jù)分離、數(shù)據(jù)驅(qū)動測試。所謂數(shù)據(jù)驅(qū)動,從它的定義來看,就是數(shù)據(jù)的改變從而驅(qū)動自動化測試的執(zhí)行,最終引起測試結(jié)果的改變。說的直白些,就是參數(shù)化的應(yīng)用。值得注意的是,ddt適用于測試數(shù)據(jù)是列表嵌套列表或者列表嵌套字典。
-
給測試數(shù)據(jù)中新增一列expected,用于添加斷言的預(yù)期結(jié)果
image -
修改do_excel.py,讀取expected的數(shù)據(jù):
get_data()方法中新增:
sub_data["expected"] = sheet.cell(i, 6).value
write_back_data()方法中修改:sheet.cell(i,7).value=value
-
改造測試用例
test_http_request.py
import unittest from common.public.http_request import HttpRequest from ddt import ddt,data from common.public.do_excel import DoExcel test_data=DoExcel().get_data("../../test_data/test_data.xlsx","Sheet1") @ddt class TestHttpRequest(unittest.TestCase): def setUp(self): pass def tearDown(self): pass @data(*test_data) def test_login(self,item): #添加item,即測試數(shù)據(jù) res=HttpRequest().http_request(item["url"],item["method"],eval(item["payload"])) self.assertEqual(str(item["expected"]),str(res.status_code)) print "獲得的結(jié)果是:",res.json()
-
改造
run.py
import HTMLTestRunner import unittest from common.public.test_http_request import TestHttpRequest suite=unittest.TestSuite() loader=unittest.TestLoader() suite.addTest(loader.loadTestsFromTestCase(TestHttpRequest)) with open("test_result/rusult.html","wb") as file: #執(zhí)行用例 runner=HTMLTestRunner.HTMLTestRunner(stream=file,verbosity=2,title="測試HttpRequest類") runner.run(suite)
問題:因為
test_http_request.py
和run.py
不是一個層級,所以這樣運(yùn)行run.py
會報錯,找不到test_data.xlsx
,所以在test_http_request.py
中的test_data
地址改為絕對路徑。but,如果設(shè)置為絕對路徑,那么在自己電腦上能跑,在別人電腦上可能會失敗。-
解決方案:路徑可配置
- os.path.split()函數(shù),將文件名和路徑分割開
- os.path.split(path)[0],取上級目錄
- os.path.join(path,*paths),拼接路徑不用加/
import os """專門讀取路徑的值""" #獲取當(dāng)前文件所在絕對路徑,包括模塊名,__file__表示是當(dāng)前文件本身 path=os.path.realpath(__file__) #獲取頂級目錄的絕對路徑 project_path=os.path.split(os.path.split(os.path.split(path)[0])[0])[0] #獲取測試數(shù)據(jù)的絕對路徑 test_data_path=os.path.join(project_path,"test_data","test_data.xlsx") #獲取測試報告的絕對路徑 test_result_path=os.path.join(project_path,"test_result","html_report","result.html")
- 使用
project_path.py
中的路徑- 引入
project_path.py
:from common.public.project_path import *
-
test_http_request.py
中:test_data=DoExcel().get_data(test_data_path,"Sheet1")
-
run.py
中:with open(test_result_path,"wb") as file:
- 引入
添加字段存入測試結(jié)果
1.result字段存放response.json()
添加:DoExcel().write_back_data(test_data_path,"Sheet1",item["case_id"]+1,str(res.json))
# encoding: utf-8
import json
import unittest
from common.public.http_request import HttpRequest
from ddt import ddt,data
from common.public.do_excel import DoExcel
from common.public.project_path import *
test_data=DoExcel().get_data(test_data_path,"Sheet1")
@ddt
class TestHttpRequest(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
@data(*test_data)
def test_login(self,item):
res=HttpRequest().http_request(item["url"],item["method"],eval(item["payload"]))
self.assertEqual(str(item["expected"]),str(res.status_code))
#將res.json寫入excel中
DoExcel().write_back_data(test_data_path,"Sheet1",item["case_id"]+1,str(res.json))
print "獲得的結(jié)果是:", res.json()
- 問題:一,報錯時,因為執(zhí)行不到print語句,從result.html中無法看出時什么問題。二,如果報錯時,res.json()就無法寫入到excel文件中。
- 解決:使用
finally
,是無論有沒有捕獲到異常都執(zhí)行finally
下的代碼(代碼在后面展示)
2.新增一個TestResult字段存放測試結(jié)果
與result字段不同,result字段存放的是response.json(),TestResult字段存入Pass/Failed,表示用例成功還是失敗。寫入excel后可以直接通過excel篩選,只查看為Failed的用例
-
首先在
test_data.xlsx
中添加字段TestResultimage -
改造測試用例
test_http_request.py
test_data=DoExcel().get_data(test_data_path,"Sheet1") @ddt class TestHttpRequest(unittest.TestCase): def setUp(self): pass def tearDown(self): pass @data(*test_data) def test_login(self,item): res=HttpRequest().http_request(item["url"],item["method"],eval(item["payload"])) #捕獲異常 try: self.assertEqual(str(item["expected"]),str(res.status_code)) #如果沒有異常, TestResult="Pass" TestResult="Pass" except AssertionError as e: #如果有異常, TestResult="Failed" TestResult = "Failed" print "測試用例失敗,{0}".format(e) raise e #無論是否捕獲異常都執(zhí)行 finally: print "獲得的結(jié)果是:", res.json() DoExcel().write_back_data(test_data_path,"Sheet1",item["case_id"]+1,str(res.json())
-
改造
do_excel.py
寫入TestResult字段def write_back_data(self,file_name,sheet_name,i,result,TestResult): wb=load_workbook(file_name) sheet=wb[sheet_name] sheet.cell(i,7).value=result sheet.cell(i,8).value=TestResult wb.save(file_name) #保存
同時,
test_http_request.py
中添加TestResult字段:
DoExcel().write_back_data(test_data_path,"Sheet1",item["case_id"]+1,str(res.json(),TestResult)
用例可配置
實現(xiàn)多個用例同時執(zhí)行、多個模塊同時執(zhí)行
配置文件效果:
[MODE]
mode={"login":"all",
"register":[1,2,4,5],
"recharge":[1,2]
}
通過option和value,配置不同的用例,option是對應(yīng)的模塊(使用不同的sheet放置不同的模塊,對應(yīng)sheetname),value的all代表該模塊所有用例,列表里的數(shù)字代表case_id,
- 新建一個配置文件
case.conf
- 寫一個讀取配置文件的類
import configparser
class ReadConfig:
@staticmethod
def get_config(file_path,setion,option):
cf=configparser.ConfigParser()
cf.read(file_path)
return cf[setion][option]
if __name__ == '__main__': #測試
from common.public import project_path
print ReadConfig.get_config(project_path.case_config_path,"MODE","mode")
控制臺輸出:
-
改造
do_excel.py
class DoExcel: @staticmethod #靜態(tài)方法,直接調(diào)用 def get_data(file_name): wb=load_workbook(file_name) mode=eval(ReadConfig.get_config(project_path.case_config_path,"MODE","mode")) test_data=[] #循環(huán)配置文件中的mode的key for key in mode: sheet=wb[key] #如果為all,跑所有的case if mode[key]=='all': for i in range(2,sheet.max_row+1): row_data={} row_data["case_id"] = sheet.cell(i, 1).value row_data["url"]=sheet.cell(i,2).value row_data["method"]=sheet.cell(i,3).value row_data["payload"]=sheet.cell(i,4).value row_data["title"]=sheet.cell(i,5).value row_data["expected"] = sheet.cell(i, 6).value #讀取sheet_name row_data["sheet_name"]=key test_data.append(row_data) else: #如果不是all,按case_id跑 for case_id in mode[key]: row_data = {} row_data["case_id"] = sheet.cell(case_id+1, 1).value row_data["url"] = sheet.cell(case_id+1, 2).value row_data["method"] = sheet.cell(case_id+1, 3).value row_data["payload"] = sheet.cell(case_id+1, 4).value row_data["title"] = sheet.cell(case_id+1, 5).value row_data["expected"] = sheet.cell(case_id+1, 6).value row_data["sheet_name"] = key test_data.append(row_data) return test_data @staticmethod def write_back_data(file_name,sheet_name,i,result,TestResult): wb=load_workbook(file_name) sheet=wb[sheet_name] sheet.cell(i,7).value=result sheet.cell(i,8).value=TestResult wb.save(file_name) #保存
-
改造測試用例
test_http_request.py
修改sheet_name參數(shù)化:
DoExcel().write_back_data(test_data_path,item["sheet_name"],item["case_id"]+1,str(res.json()),TestResult)