一. unittest常用校驗方法介紹
1.unittest模板基本概念
unittest是python內建的單元測試框架,具備編寫用例、組織用例、執行用例、輸出報告等自動化框架的條件。使用unittest前需要了解該框架的五個概念:
即test case, test suite, testLoader,test runner, test fixture。
test case :一個完整的測試單元,執行該測試單元可以完成對某一個問題的驗證,完整體現在:測試前環境準備(setUp),執行測試程式碼(run),及測試後環境還原(tearDown);
test suite :多個測試用例的集合,測試套件或測試計劃;
testLoader :載入TestCase到TestSuite中的,其中loadTestsFrom__()方法用於尋找TestCase,並建立它們的例項,然後新增到TestSuite中,返回TestSuite例項;
test runner :執行測試用例,並將測試結果儲存到TextTestResult例項中,包括執行了多少測試用例, 成功了多少,失敗了多少等資訊;
test fixture:一個測試用例的初始化準備及環境還原,主要是setUp() 和 setDown()方法;
2.unittest模板基本介紹
1.簡單的unittest的使用
#首先匯入unittest import unittest class testUnittestOne(unittest.TestCase): #編寫測試用例,方法名必須以test開頭 def test_equals(self): self.assertEquals(1,1,msg="相等") #執行測試用例 if __name__ == '__main__': unittest.main()
2.testCase多個之間的執行順序,按照測試用例的方法名字母進行排序執行的;每條用例執行前都會執行一下setUp方法,用例執行後都還會在執行一遍tearDown方法
import unittest class testUnittestTwo(unittest.TestCase): #測試用例初始化方法setUp def setUp(self): print("開始執行測試用例") #測試用例後置方法tearDown def tearDown(self): print("執行完測試用例") def test_case1(self): print("執行case1") self.assertEqual(1,1,msg="1等於1") def test_aase2(self): print("執行case2") self.assertEqual(1, 2, msg="1不等於2") if __name__ == '__main__': unittest.main()
執行結果:
3.setUpClass、tearDownClass類方法分別是該測試類執行前的初始化方法和後置方法
import unittest class testUnittestTwo(unittest.TestCase): #測試用例初始化方法setUp @classmethod def setUpClass(self): print("開始執行測試用例") #測試用例後置方法tearDown @classmethod def tearDownClass(self): print("執行完測試用例") def test_case1(self): print("執行case1") self.assertEqual(1,1,msg="1等於1") def test_aase2(self): print("執行test_aase2") self.assertEqual(1, 2, msg="1不等於2") if __name__ == '__main__': unittest.main()
執行結果:
3.unittest模板常用校驗方法
二. unittest介面引數化及用例集介紹
1.unittest引數化
import unittest import requests import parameterized # 資料引數化需要匯入該模組 import HTMLTestRunner class LoginTest(unittest.TestCase): url = "http://api.nnzhp.cn/api/user/login" # 測試資料進行引數化 @parameterized.parameterized.expand([ ["niuhanyang", "aA123456"], ["niuhanyang", "aA1234567"], ["niuhanyang", "aA1234568"] ]) def test_login(self, username, password): data = {"username": username, "passwd": password} re = requests.post(self.url, data).text self.assertIn("userId", re, "包含userId") if __name__ == '__main__': # 把測試用例放在測試集合中 suite = unittest.makeSuite(LoginTest) f = open("report.html", "wb") # 生成測試報告,需要先匯入HTMLTestRunner模板,放在當前目錄下或python第三方模板安裝的site_package資料夾下 runner = HTMLTestRunner.HTMLTestRunner(f, description="baogao", title="") runner.run(suite) f.close()
執行結果:
2.unittest透過讀取檔案內容進行引數化
定義user.txt檔案,檔案每行定義三個引數,逗號進行分割;
import unittest import parameterized import requests import HTMLTestRunner class TestParameFile(unittest.TestCase): url = 'http://api.nnzhp.cn/api/user/login' """ 透過檔案進行引數化 """ def getDataForFile(fileName): data = [] with open(fileName, encoding="utf-8") as fw: for line in fw: line = line.strip() if line: data.append(line.split(",")) return data @parameterized.parameterized.expand(getDataForFile("users.txt")) def test_login(self, username, password, check): # 傳送介面請求 re = requests.post(self.url, {"username": username, "passwd": password}).text self.assertIn(check, re, "沒有返回%s" % check) if __name__ == "__main__": # 生成測試用例套件 testSuit = unittest.makeSuite(TestParameFile) f = open("testParameFile.html", "wb") Runner = HTMLTestRunner.HTMLTestRunner(f, title="測試報告", description="測試報告詳情") Runner.run(testSuit) f.close()
執行結果:
3.unittest多個用例集執行
建立case資料夾,在case資料夾下定義多個測試用例類
import unittest import HTMLTestRunner import time import BeautifulReport class RunManyTestCase(unittest.TestCase): def runTestCase(self): # 將測試用例載入到caseSuite中 caseSuite = unittest.defaultTestLoader.discover("case", "*") f = open("manyReport%s.html" % (time.strftime("%y%m%d")), "wb") runCase = HTMLTestRunner.HTMLTestRunner(f, title="用例集報告", description="xxx系統測試報告") runCase.run(caseSuite) f.close() def runTestCaseReport(self): # 將測試用例載入到caseSuite中 caseSuite = unittest.defaultTestLoader.discover("case", "*") bf = BeautifulReport.BeautifulReport(caseSuite) bf.report(description='查詢測試用例的', filename='discover%s.html' % (time.time())) if __name__=="__main__": c = RunManyTestCase() c.runTestCase() c.runTestCaseReport()
4.unittest透過HTMLTestRunner進行生成報告
import unittest import HTMLTestRunner import time import BeautifulReport class RunManyTestCase(unittest.TestCase): def runTestCase(self): # 將測試用例載入到caseSuite中 caseSuite = unittest.defaultTestLoader.discover("case", "*") f = open("manyReport%s.html" % (time.strftime("%y%m%d")), "wb") runCase = HTMLTestRunner.HTMLTestRunner(f, title="用例集報告", description="xxx系統測試報告") runCase.run(caseSuite) f.close() def runTestCaseReport(self): # 將測試用例載入到caseSuite中 caseSuite = unittest.defaultTestLoader.discover("case", "*") bf = BeautifulReport.BeautifulReport(caseSuite) bf.report(description='查詢測試用例的', filename='discover%s.html' % (time.time())) if __name__=="__main__": c = RunManyTestCase() c.runTestCase()
執行結果:
5.unittest透過BeautifulReport進行生成報告
import unittest import HTMLTestRunner import time import BeautifulReport class RunManyTestCase(unittest.TestCase): def runTestCase(self): # 將測試用例載入到caseSuite中 caseSuite = unittest.defaultTestLoader.discover("case", "*") f = open("manyReport%s.html" % (time.strftime("%y%m%d")), "wb") runCase = HTMLTestRunner.HTMLTestRunner(f, title="用例集報告", description="xxx系統測試報告") runCase.run(caseSuite) f.close() def runTestCaseReport(self): # 將測試用例載入到caseSuite中 caseSuite = unittest.defaultTestLoader.discover("case", "*") # 生成測試報告,需要先匯入BeautifulReport模板,放在當前目錄下或python第三方模板安裝的site_package資料夾下 bf = BeautifulReport.BeautifulReport(caseSuite) bf.report(description='查詢測試用例的', filename='discover%s.html' % (time.time())) if __name__=="__main__": c = RunManyTestCase() c.runTestCaseReport()
執行結果:
附件:HTMLTestRunner.py檔案和BeautifulReport.zip壓縮吧
6.unittest建立有關聯關係的介面
import unittest import parameterized class Case(unittest.TestCase): def login(self,userid): return userid @parameterized.parameterized.expand([ [222], [333] ]) def test_login(self,userid): "ss" userid=self.login(userid) return self.assertEqual(userid,222,'成功') suite=unittest.makeSuite(Case) import BeautifulReport.BeautifulReport bf=BeautifulReport.BeautifulReport(suite) bf.report(description="測試報告",filename='關聯關係的.html')
三. unittest封裝介面自動化框架
1.需求分析
utp介面自動化框架:
a.介面自動化測試用例放在cases目錄下且case開頭進行命名,涉及到有關聯關係的介面可以先定義基類
b.介面自動化測試用例需要與介面分離,因此需要進行引數化,資料放在datas目錄下
c.查詢所有測試介面進行執行,執行成功後傳送郵件
2.程式碼編寫
a.先分別建立bin、cases、configs、datas、libs、logs、reports資料夾,bin目錄進行存放程式主入口,cases目錄下
存放介面測試用例;configs目錄下進行存放配置檔案;datas目錄下進行存放介面測試資料;libs目錄下進行存放常用功能;logs目錄下進行存放日誌檔案;reports進行存放介面自動化測試報告
b.libs資料夾下定義toos.py
import os import jsonpath from configs.Settings import T0,CC,EMAIL_INFO,LOG,DATAS_PATH import traceback,time,yagmail def get_value(d,k): # 透過jsonpath.jsonpath來取字典中key所對應的值 result=jsonpath.jsonpath(d,'$..%s'%k) # 如果取到了返回第一個值,否則返回空字串 if result: return result[0] return '' def send_email(pass_count,fail_count,file_name): LOG.debug("開始傳送報告了,檔名是%s"%file_name) content=''' 各位好: 本次介面自動化測試結果如下,總共執行%s條用例,透過%s條,失敗【%s】條。 詳情請檢視附件。 '''%((pass_count+fail_count),pass_count,fail_count) subject='%s-介面測試報告'%time.strftime("%Y-%m-%d %H%M%S") email=yagmail.SMTP(**EMAIL_INFO,encoding="GBK") try: email.send(to=T0,cc=CC,subject=subject,contents=content,attachments=file_name) except Exception as e: LOG.error("傳送報告失敗,具體失敗原因是%s"%traceback.format_exc()) else: LOG.debug("報告傳送成功") def get_data_from_text(file_name): """獲取引數化資料""" data=[] file_name=os.path.join(DATAS_PATH,file_name) with open(file_name,encoding='utf-8') as fr: for line in fr: line=line.strip() if line: data.append(line.split(",")) return data def get_data_from_excel(file_name): """獲取引數化資料""" pass def get_data_from_db(file_name): """獲取引數化資料""" pass def get_data_from_redis(file_name): """獲取引數化資料""" pass
c.configs資料夾下定義Settings.py檔案
import os # 傳送郵件 EMAIL_INFO={ "user":"13424210282@163.com", "password":"HLXWWGTUWGNAAAEA", "host":"smtp.163.com", } # 郵件接收人 T0=["974219141@qq.com"] # 郵件抄送人 CC=['751462075@qq.com'] # 介面請求url地址配置 host_map={ "fat":"http://127.0.0.1:8787", "uat":"", "pro":"" } default="fat" HOST=host_map.get(default) # 自動化專案父目錄 BASE_PATH=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 測試用例目錄 CASE_PATH=os.path.join(BASE_PATH,'cases') # 日誌檔案目錄 LOG_PATH=os.path.join(BASE_PATH,"logs",'utp.log') import nnlog LOG=nnlog.Logger(LOG_PATH) # 測試報告目錄 REPORT_PATH=os.path.join(BASE_PATH,'reports') # 查詢用例 DATAS_PATH=os.path.join(BASE_PATH,'datas')
d.cases資料夾下定義case_login.py檔案(沒有關聯關係)
1.沒關聯關係的介面
import unittest import parameterized from libs.tools import get_data_from_text import requests from configs.Settings import HOST from urllib.parse import urljoin class CaseTestLogin(unittest.TestCase): # 拼接介面請求url url=urljoin(HOST,"/login") # 進行引數,透過get_data_from _text獲取login.txt檔案 @parameterized.parameterized.expand(get_data_from_text("login.txt")) def test_login(self,user,password,check): data={"username":user,"password":password} headers={"Content-Type":"application/json"} # 傳送介面請求 r=requests.post(self.url,json=data,headers=headers).text # 校驗check引數的值是否在介面返回的字串中 self.assertIn(check,r,"%s在%s中"%(check,r))
2.有關聯關係的介面,先在BaseCase.py檔案中定義基類Base_Case
import unittest import requests from configs.Settings import HOST from urllib.parse import urljoin from libs.tools import get_value class Base_Case(unittest.TestCase): def login(self,user,password,check): data = {"username": user, "password": password} headers = {"Content-Type": "application/json"} # 傳送介面請求 r = requests.post(urljoin(HOST,"/login"), json=data, headers=headers) # 校驗 self.assertIn(check, r.text, "%s在%s中" % (check, r.text)) # 獲取介面請求返回的tokenId並進行返回 tokenId=get_value(r.json(),'tokenId') return tokenId
在定義case_pay.py檔案中Case_Pay類繼承Base_Case類
import unittest import requests from cases import BaseCase from configs.Settings import HOST from urllib.parse import urljoin from parameterized import parameterized from libs.tools import get_data_from_text class Case_Pay(BaseCase.Base_Case): @parameterized.expand(get_data_from_text("pay.txt")) def test_pay(self,user,password,check,money): """支付成功""" tokenId=self.login(user,password,check) data={"username":user,"money":money} headers={"tokenId":tokenId} r=requests.post(urljoin(HOST,"/pay"),json=data,headers=headers) self.assertIn("支付成功",r.text,)
e.datas資料夾下定義login.txt和pay.txt檔案
f.bin目錄下定義程式執行start.py檔案
import sys,os import time BASE_PATH=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0,BASE_PATH) import unittest import BeautifulReport from libs.tools import send_email from configs.Settings import REPORT_PATH,CASE_PATH def run(): suite=unittest.defaultTestLoader.discover(CASE_PATH,"case*.py") bf=BeautifulReport.BeautifulReport(suite) filename="utp報告%s.html"%(time.strftime("%Y%m%d%H%M%S")) report_path=os.path.join(REPORT_PATH,filename) bf.report(description="utp測試報告",filename=filename,log_path=REPORT_PATH) send_email(bf.success_count,bf.failure_count,report_path) if __name__ == '__main__': run()
最後執行bin目錄下的start.py檔案,可以正常看到測試報告