???????本文是《手把手教你用Python實(shí)現(xiàn)接口自動化測試》這一系列文章的開篇悼尾,筆者將從本文開始給大家介紹一下如何使用Python實(shí)現(xiàn)接口自動化測試滓鸠,希望能起到一個(gè)拋磚引玉的作用。
???????在《手把手教你用Python實(shí)現(xiàn)接口自動化測試》這一系列文章將會分成3個(gè)部分:
??????????????1. 開篇:介紹Python實(shí)現(xiàn)接口自動化的實(shí)現(xiàn)思路,項(xiàng)目結(jié)構(gòu)以及展示最終實(shí)現(xiàn)的效果萌焰;
??????????????2. 支線文章:針對項(xiàng)目中所用到的知識點(diǎn)分別進(jìn)行展開介紹总放;
??????????????3. 完結(jié)篇:我將在最后一篇文章中對項(xiàng)目中各個(gè)細(xì)節(jié)進(jìn)行詳細(xì)闡述呈宇。
前言
???????開篇文章中我們先主要來說一說在開始寫實(shí)際業(yè)務(wù)代碼之前的一些準(zhǔn)備工作,介紹一下使用Python實(shí)現(xiàn)接口自動化的實(shí)現(xiàn)思路局雄。在這個(gè)系列文章里不會教您Python
的基礎(chǔ)知識甥啄,如果您知道一些簡單的編碼知識或者進(jìn)行一定的Python基礎(chǔ)學(xué)習(xí)后會有助于您對本系列文章的閱讀。
一炬搭、為什么需要實(shí)現(xiàn)接口自動化測試蜈漓?
首先穆桂,我們先看一下正常的接口測試流程是什么?
???????這其中可以實(shí)現(xiàn)接口測試的工具有很多融虽,例如:如postman享完、jmeter、fiddler等等有额,這些工具使用起來非常方便般又,功能也很多。
那么為什么還要寫代碼實(shí)現(xiàn)接口自動化呢谆吴?
-
工具雖然方便倒源,但也其不足之處:
1. 測試數(shù)據(jù)不可控制
接口測試本質(zhì)其實(shí)是對數(shù)據(jù)的驗(yàn)證:我們調(diào)用接口,輸入接口請求需要的一些數(shù)據(jù)句狼,接口返回一些數(shù)據(jù)笋熬,然后我們針對接口返回?cái)?shù)據(jù)驗(yàn)證正確性。在用工具運(yùn)行測試用例之前不得不手動向數(shù)據(jù)庫中插入測試數(shù)據(jù)腻菇。這樣我們的接口測試是不是就沒有那么“自動化了”胳螟。
2. 回歸測試耗時(shí)
這是功能測試的一大硬傷,測試人員往往無法面對成百上千條測試case的回歸需求筹吐,而大部分開發(fā)在完成一個(gè)改動時(shí)都會捎帶一句“全量回歸一下糖耸,看看有沒有其他問題”。其次即使我們的測試人員比較給力認(rèn)真丘薛,完成了回歸測試嘉竟,但這其中難免不會有失誤或者遺漏之處。機(jī)器卻能任勞任怨的執(zhí)行每一條case且保證每次都能按照流程進(jìn)行測試洋侨。
3. 擴(kuò)展能力不足
當(dāng)我們在享受工具所帶來的便利的同時(shí)舍扰,往往也會受制于工具所帶來的局限。例如希坚,我想將測試結(jié)果生 成 HMTL 格式測試報(bào)告边苹,我還想將測試報(bào)告發(fā)送到指定郵箱等等,這些需求都是工具難以實(shí)現(xiàn)的裁僧。
那么我們期望的接口自動化測試流程是什么樣的个束?
本系列文章中介紹的接口自動化測試框架還能做什么?
???????1:測試數(shù)據(jù)源可以是多樣性的
???????2:多種結(jié)果驗(yàn)證方式
???????當(dāng)然我們還可以將測試結(jié)果處理為HTML格式的報(bào)告以郵件的形式發(fā)送至指定郵箱聊疲。
???????那么接下來茬底,我們就根據(jù)這樣的過程來一步步搭建我們的框架。在這個(gè)過程中获洲,我們需要做到業(yè)務(wù)和數(shù)據(jù)的分離阱表,這樣才能靈活,達(dá)到我們實(shí)現(xiàn)接口自動化目的。
二捶枢、測試需求梳理
???????無論是正常測試還是實(shí)現(xiàn)接口測試自動化握截,我們都應(yīng)該優(yōu)先將需求梳理清晰,這樣才能在執(zhí)行的過程中確保不會有偏差烂叔。
???????本文將以QQ音樂PC版中歌手列表和排行榜相關(guān)功能做示例谨胞,示例截圖如下:
QQ音樂PC版首頁傳送門
QQ音樂PC版-歌手首頁
通過簡單的頁面分析,我們可以獲取歌手列表相關(guān)接口信息:
1. 歌手列表首頁
1.1 歌手列表首頁接口請求信息
通過cur_page字段的值控制請求頁數(shù)蒜鸡,一頁返回80條
第一頁
https://u.y.qq.com/cgi-bin/musicu.fcg?-=getUCGI1473476396452713&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8?ice=0&platform=yqq.json&needNewCode=0&data={"comm":{"ct":24,"cv":0},"singerList":{"module":"Music.SingerListServer","method":"get_singer_list","param":{"area":-100,"sex":-100,"genre":-100,"index":-100,"sin":0,
"cur_page":1
}}}第二頁
https://u.y.qq.com/cgi-bin/musicu.fcg?-=getUCGI9803531398820899&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8?ice=0&platform=yqq.json&needNewCode=0&data={"comm":{"ct":24,"cv":0},"singerList":{"module":"Music.SingerListServer","method":"get_singer_list","param":{"area":-100,"sex":-100,"genre":-100,"index":-100,"sin":80,
"cur_page":2
}}}
1.2 歌手列表首頁接口返回信息
2. 歌手熱門歌曲列表
2.1 周杰倫-熱門歌曲列表接口請求信息
通過singermid字段的值控制請求的歌手歌曲列表
通過sin胯努,num字段的值控制請求列表數(shù)量,默認(rèn)返回10條
https://u.y.qq.com/cgi-bin/musicu.fcg?-=getUCGI3347917939773577&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8?ice=0&platform=yqq.json&needNewCode=0&data={"comm":{"ct":24,"cv":0},"singer":{"method":"get_singer_detail_info","param":{"sort":5,
"singermid":"0025NhlN2yWrP4"
,"sin":0
,"num":10
},"module":"music.web_singer_info_svr"}}
2.2 周杰倫-熱門歌曲列表接口返回信息
3. 歌手專輯列表
3.1 周杰倫-專輯列表接口請求信息
通過singermid字段的值控制請求的歌手歌曲列表
通過begin逢防,num字段的值控制請求列表數(shù)量叶沛,默認(rèn)返回5條
https://u.y.qq.com/cgi-bin/musicu.fcg?-=getUCGI3111122848094381&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8?ice=0&platform=yqq.json&needNewCode=0&data={"comm":{"ct":24,"cv":0},"singerAlbum":{"method":"get_singer_album","param":{
"singermid":"0025NhlN2yWrP4"
,"order":"time","begin":0
,"num":5
,"exstatus":1},"module":"music.web_singer_info_svr"}}
3.2 周杰倫-專輯列表接口返回信息
QQ音樂PC版-排行榜首頁
讓我們再通過簡單的頁面分析,我們可以獲取排行榜相關(guān)接口信息:
4. 排行榜
4.1 流行指數(shù)榜-歌曲列表接口請求信息
通過topId字段的值控制請求的榜單列表
通過offset忘朝,num字段的值控制請求列表數(shù)量灰署,默認(rèn)返回20條
https://u.y.qq.com/cgi-bin/musicu.fcg?-=getUCGI2506723965565383&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8?ice=0&platform=yqq.json&needNewCode=0&data={"detail":{"module":"musicToplist.ToplistInfoServer","method":"GetDetail","param":{
"topId":4
,"offset":0
,"num":20
,"period":"2019-08-14"}},"comm":{"ct":24,"cv":0}}
4.2 流行指數(shù)榜-歌曲列表接口請求信息
最后,通過以上簡單的分析局嘁,我們設(shè)定有如下測試需求:
三溉箕、項(xiàng)目搭建
???????我們把搭建一個(gè)項(xiàng)目比喻成建造一間房屋,其中我們需要先為房屋建立基礎(chǔ)和框架(項(xiàng)目結(jié)構(gòu))就像是先建成一座毛坯房悦昵。
我們在建造房屋時(shí)所使用到的工具:
-
編程語言:Python 3.7
-
編譯器:?Pycharm
-
項(xiàng)目框架:Flask
-
測試框架:Unittest
使用Pycharm創(chuàng)建Flask項(xiàng)目后肴茄,我們建立如下項(xiàng)目結(jié)構(gòu):
********項(xiàng)目中各個(gè)文件作用********
common
------存放公共的方法文件
config
------存放配置文件
testcase
---存放具體的測試case
testdata
---存放相關(guān)測試數(shù)據(jù)
testresult
---存放測試報(bào)告和日志文件
testrunner
---用例執(zhí)行的入口文件
util
----------私有工具文件
app.py
-------接口入口文件
現(xiàn)在我們有了一間光禿禿的毛坯房,里面什么都沒有但指,那么接下來我們需要對其進(jìn)行裝修使其擁有較為舒適的居住條件寡痰。
1. 首先我們從比較容易的config
文件入手
config目錄下有2個(gè).ini
信息配置文件,以及2個(gè)用于讀取配置文件信息的.py
文件棋凳。
1.1 配置文件信息
commoninfo.ini
文件配置信息如下(配置了各個(gè)api接口的請求參數(shù)信息)
[UrlInfo_QQMusic]---接口請求Url信息分組標(biāo)識
apibaseurl = https://u.y.qq.com/cgi-bin/musicu.fcg?-=getUCGI1473476396452713&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&data=
data_singerlist = {"comm":{"ct":24,"cv":0},"singerList":{"module":"Music.SingerListServer","method":"get_singer_list","param":{"area":-100,"sex":-100,"genre":-100,"index":-100,"sin":0,"cur_page":1}}}
data_songlist = {"comm":{"ct":24,"cv":0},"singer":{"method":"get_singer_detail_info","param":{"sort":5,"singermid":"0025NhlN2yWrP4","sin":0,"num":10},"module":"music.web_singer_info_svr"}}
data_albumlist = {"comm":{"ct":24,"cv":0},"singerAlbum":{"method":"get_singer_album","param":{"singermid":"0025NhlN2yWrP4","order":"time","begin":0,"num":5,"exstatus":1},"module":"music.web_singer_info_svr"}}
data_weeklist = {"comm":{"ct":24,"cv":0},"request":{"method":"get_history_key_list","param":{"periods":5},"module":"video.VideoRankServer"}}
data_toplist = {"detail":{"module":"musicToplist.ToplistInfoServer","method":"GetDetail","param":{"topId":4,"offset":0,"num":20,"period":"2019-08-14"}},"comm":{"ct":24,"cv":0}}
dbconfig.ini
文件配置信息如下(配置了數(shù)據(jù)庫連接參數(shù))
[DataBase_ConnectInfo]---數(shù)據(jù)庫連接參數(shù)分組標(biāo)識
host = **********你需要操作的數(shù)據(jù)庫DB連接串
port = **********DB端口號
dbname = ********DB名稱
username = ******DB連接賬號
password = ******DB連接密碼
1.2 讀取配置文件
讀取配置文件信息思路:
使用configparser
對象在對應(yīng)配置文件中根據(jù)分組標(biāo)識獲取相關(guān)配置參數(shù)
以readdbconfig.py
為例拦坠,其讀取dbconfig.ini
文件信息的代碼如下:
currentfile_path = os.path.split(os.path.realpath(__file__))[0]
"""拼接config.ini文件的路徑地址"""
dbconfig_path = os.path.join(currentfile_path, "dbconfig.ini")
"""實(shí)例化configParser對象"""
self.cf = configparser.ConfigParser()
"""讀取config.ini文件"""
self.cf.read(dbconfig_path, encoding="utf-8")
"""根據(jù)配置文件中的分組標(biāo)識獲取配置參數(shù)信息"""
connectinfo = dict(self.cf.items('DataBase_ConnectInfo'))
2. 下面我們看看common
目錄下面都有哪些公共方法
2.1 excutesql.py
文件用于數(shù)據(jù)庫中進(jìn)行sql語句的執(zhí)行操作
該封裝方法進(jìn)行了數(shù)據(jù)庫的連接操作,外部調(diào)用只需傳入需要執(zhí)行的sql語句即可
2.2 getlogger.py
文件用于創(chuàng)建logger對象
該封裝方法創(chuàng)建了一個(gè)
logger
對象贫橙,供所有case執(zhí)行時(shí)進(jìn)行相關(guān)信息日志的記錄
2.3 gettestdata.py
文件用于獲取case執(zhí)行時(shí)的測試數(shù)據(jù)
該封裝方法是我們實(shí)現(xiàn)數(shù)據(jù)分離的核心
主要通過獲取
api接口
/mysql
/excel文件
/config配置文件
中的數(shù)據(jù)贪婉,然后將數(shù)據(jù)轉(zhuǎn)成我們case執(zhí)行時(shí)需要的數(shù)據(jù)格式
當(dāng)前項(xiàng)目中我每個(gè)接口分別使用了不同的數(shù)據(jù)源獲取方式進(jìn)行演示反粥,在實(shí)際項(xiàng)目中可根據(jù)情況選擇相應(yīng)的數(shù)據(jù)源獲取方式卢肃。
2.4 MyHTMLTestRunner.py
文件用于將測試結(jié)果生成*.html
格式的測試報(bào)告
該文件為網(wǎng)上其他大神的作品,我進(jìn)行了些許的改動才顿,就不提供源碼了莫湘,大家可自行g(shù)oogle即可
2.5 sendemail.py
文件用于將測試結(jié)果郵件的形式發(fā)送至指定郵箱地址
該封裝方法是將我們測試結(jié)果(包含
*.html
和*.log
附件)通過郵件的形式發(fā)送至指定接收人
其中郵件收件人:recipients
、郵件抄送人:cc
信息郑气,我這邊是通過在上文commoninfo.ini
文件中進(jìn)行配置幅垮,使用configparser
對象進(jìn)行讀取
#commoninfo.ini中信息---多個(gè)收件人、抄送人以分號隔開
[EMAIL_OUTLOOK]------郵件配置參數(shù)信息分組標(biāo)識
recipients = ***1@***.***; ***2@***.***;
cc = ***1@***.***; ***2@***.***;
3. 我們現(xiàn)在看看測試數(shù)據(jù)testdata
目錄有哪些內(nèi)容
testdata
目錄下一般存放的是一些靜態(tài)的 測試數(shù)據(jù)文件尾组;文件類型不固定,如:.txt
忙芒、.xls
示弓、.xml
、.json
都能支持呵萨;
思路就是通過各個(gè)文件的類庫方法從文件中讀寫數(shù)據(jù)后奏属,通過gettestdata.py
封裝成我們最終需要的測試數(shù)據(jù)格式。
4. util
中放的是一些私有工具類
util
中的工具類一般都是針對當(dāng)前項(xiàng)目封裝的一些測試工具類潮峦,對于別的項(xiàng)目可能就不太適用囱皿。
本文中筆者針對excel
文件進(jìn)行讀寫封裝了一個(gè)簡單工具類operateexcel.py
5. 實(shí)際的測試case文件
????上面我們有看到測試數(shù)據(jù)參數(shù)的設(shè)置,測試數(shù)據(jù)的獲取方式等等忱嘹,但這些都是前置條件嘱腥,而實(shí)際的測試case是什么樣的呢?
我們將測試用例case維護(hù)在testcase
文件目錄下
首先我這邊根據(jù)測試接口類型進(jìn)行了分類:排行榜相關(guān)接口拘悦、歌手相關(guān)接口齿兔;
然后每個(gè)接口單獨(dú)一個(gè)
.py
文件進(jìn)行具體測試case的編寫。
本文編寫case時(shí)采用的是
python
自帶的unittest
測試框架對case進(jìn)行驅(qū)動執(zhí)行础米。
每個(gè)case文件在被執(zhí)行之前需求進(jìn)行測試數(shù)據(jù)的初始化愧驱;
測試數(shù)據(jù)通過parameterized
進(jìn)行參數(shù)化傳參;
使用assertEqual
進(jìn)行斷言驗(yàn)證椭盏。
以
singerlist.py
為例:該文件為“驗(yàn)證每個(gè)歌手基本信息中各個(gè)字段的信息”測試case
@parameterized.expand(testdata['singerinfo_list'])
def test_Country_Null(self, singerinfo):
"""
驗(yàn)證每個(gè)歌手信息中的country不為空
:param singerinfo:
:return:
"""
country = singerinfo['country']
if country:
self.assertEqual(True, True)
else:
print(singerinfo)
self.logger.info('singerinfo_test_Country_Null:' + str(singerinfo))
self.assertEqual(True, False)
@parameterized.expand(testdata['singerinfo_list'])
def test_Singer_Id_Type(self, singerinfo):
"""
驗(yàn)證每個(gè)歌手信息中的singer_id數(shù)據(jù)類型為數(shù)字
:param singerinfo:
:return:
"""
singer_id = singerinfo['singer_id']
if singer_id.__class__.__name__ == 'int':
self.assertEqual(True, True)
else:
print(singerinfo)
self.logger.info('singerinfo_test_Singer_Id_Type:' + str(singerinfo))
self.assertEqual(True, False)
@parameterized.expand(testdata['singerinfo_list'])
def test_Singer_Mid_Len(self, singerinfo):
"""
驗(yàn)證每個(gè)歌手信息中的singer_mid數(shù)據(jù)長度
:param singerinfo:
:return:
"""
singer_mid = singerinfo['singer_mid']
if len(singer_mid) == 14:
self.assertEqual(True, True)
else:
print(singerinfo)
self.logger.info('singerinfo_test_Singer_Mid_Len:' + str(singerinfo))
self.assertEqual(True, False)
@parameterized.expand(testdata['singerinfo_list'])
def test_Singer_Name_Type(self, singerinfo):
"""
驗(yàn)證每個(gè)歌手信息中的singer_name數(shù)據(jù)類型
:param singerinfo:
:return:
"""
singer_name = singerinfo['singer_name']
if singer_name.__class__.__name__ == 'str':
self.assertEqual(True, True)
else:
print(singerinfo)
self.logger.info('singerinfo_test_Singer_Name_Type:' + str(singerinfo))
self.assertEqual(True, False)
@parameterized.expand(testdata['singerinfo_list'])
def test_Singer_Pic_Info(self, singerinfo):
"""
驗(yàn)證每個(gè)歌手信息中的singer_pic數(shù)據(jù)內(nèi)容
:param singerinfo:
:return:
"""
singer_pic = singerinfo['singer_pic']
singer_mid = singerinfo['singer_mid']
exceptvalue = 'http://y.gtimg.cn/music/photo_new/T001R150x150M000' + singer_mid + '.webp'
if singer_pic == exceptvalue:
self.logger.info('singerinfo_test_Singer_Pic_Info:' + str(singerinfo))
self.assertEqual(True, True)
else:
print(singerinfo)
self.assertEqual(True, False)
四组砚、測試case的執(zhí)行
1. 如何執(zhí)行維護(hù)的測試case
???????經(jīng)過前面的操作,我們現(xiàn)在有了一間裝修完的房子掏颊,里面有家具家電糟红,現(xiàn)在我們要做的就是給它上通上水電煤,讓它能運(yùn)轉(zhuǎn)起來滿足我們持續(xù)居住的條件乌叶。同樣盆偿,我們的測試case也需要被執(zhí)行才能實(shí)現(xiàn)其存在的意義,下面我們來看看我們的測試case如何被驅(qū)動執(zhí)行的准浴。
我們將測試用例執(zhí)行文件維護(hù)在testrunner
文件目錄下
我們可以在
caserunner_myhtml.py
文件中定制我們的case執(zhí)行方式:
- 執(zhí)行所有接口的測試case
- 根據(jù)接口名稱執(zhí)行測試case
def runall(self):
"""1.根據(jù)當(dāng)前文件路徑獲得case執(zhí)行時(shí)的路徑事扭、報(bào)告名稱信息"""
pathinfo_dict = TestData().get_pathinfo_dict(__file__)
"""2.初始化測試套件"""
testsuite = unittest.TestSuite()
"""3.遍歷appidlist中的應(yīng)用appid,獲取對應(yīng)應(yīng)用下所有接口case乐横,并添加進(jìn)測試套件testsuite中"""
global discover, case_list
case_list = [] # 當(dāng)前appid下對應(yīng)的測試用例列表
"""3-1.拼接當(dāng)前appid的用例路徑"""
filepath_testcase = pathinfo_dict['filepath_testcase']
"""3-2.使用os.walk方法遍歷得到所有文件名稱filename的列表集合"""
for dirpath, dirname, filename in os.walk(filepath_testcase):
for file in filename:
# 判斷文件以.py結(jié)尾且不以__開始求橄,為去除__init.py文件和.pyx后綴的文件
if file.endswith(".py") and not file.startswith("__"):
# print(file)
case_list.append(file)
"""3-3.使用unittest.defaultTestLoader.discover()方法,根據(jù)路徑和case名稱尋找對應(yīng)的case信息"""
for case in case_list:
discover = unittest.defaultTestLoader.discover(start_dir=filepath_testcase,
pattern=case,
top_level_dir=filepath_testcase)
"""3-4.將找到的case添加至測試套件中"""
testsuite.addTest(discover)
"""4.執(zhí)行所有測試套件testsuite中所有測試用例葡公,生成報(bào)告罐农,并將報(bào)告發(fā)送至指定郵箱地址"""
self.run_and_sendemail(testsuite, pathinfo_dict['reportpath'])
def runall_bycaselist(self, caselist):
"""
通過根據(jù)傳入的case名稱列表進(jìn)行所有case的執(zhí)行
1.傳入多個(gè)case名稱即為執(zhí)行列表中所有接口case
2.傳入單個(gè)case名稱即執(zhí)行case下所有接口case
:param caselist:
:return:
"""
"""1.根據(jù)當(dāng)前文件路徑獲得case執(zhí)行時(shí)的路徑、報(bào)告名稱信息"""
pathinfo_dict = TestData().get_pathinfo_dict(__file__)
"""2.初始化測試套件"""
testsuite = unittest.TestSuite()
"""3.遍歷caselist中的case名稱催什,獲取對應(yīng)接口case涵亏,并添加進(jìn)testsuite"""
for case in caselist:
global discover
"""
3-1.使用unittest.defaultTestLoader.discover()方法,根據(jù)路徑和case名稱尋找對應(yīng)的case信息;
filepathdict['filepath_testcase']對應(yīng)為filepath_testcase
case對應(yīng)的文件名稱
"""
discover = unittest.defaultTestLoader.discover(start_dir=pathinfo_dict['filepath_testcase'],
pattern=case + '.py',
top_level_dir=None)
"""3-2.將找到的case添加至測試套件中"""
testsuite.addTest(discover)
"""4.執(zhí)行所有測試套件testsuite中所有測試用例气筋,生成報(bào)告拆内,并將報(bào)告發(fā)送至指定郵箱地址"""
self.run_and_sendemail(testsuite, pathinfo_dict['reportpath'])
2. 生成測試報(bào)告
本文中,我們在
caserunner_myhtml.py
文件將用例的執(zhí)行宠默、測試報(bào)告的生成矛纹、以及郵件的發(fā)送進(jìn)行了封裝。
可在testresult
文件目錄下查看測試報(bào)告和日志文件信息光稼。
???????到目前為止我們其實(shí)已經(jīng)實(shí)現(xiàn)了目標(biāo)因谎,但是以上操作都是在本地環(huán)境進(jìn)行執(zhí)行的状囱,接下來我們還需要考慮如何讓該工具被所有人使用璃哟,才能實(shí)現(xiàn)其最大的價(jià)值吗购。
3. 使用接口進(jìn)行調(diào)用
一般我們實(shí)現(xiàn)了一個(gè)測試工具,往往不能只考慮是提供給測試人員使用(或者說只是編寫測試用例的同學(xué)才會使用)冰垄;
我們希望開發(fā)人員或者其他相關(guān)人員都能使用蹬癌,但是他們又無需在本地部署代碼;
所以我們需要考慮如何將測試工具變得容易操作虹茶,比如只需調(diào)用接口就能執(zhí)行相關(guān)用例逝薪;
這個(gè)就是我們?yōu)槭裁词褂肍lask進(jìn)行項(xiàng)目搭建的原因:
我們使用Flask進(jìn)行實(shí)現(xiàn)了簡單的restful風(fēng)格的接口服務(wù),在內(nèi)部調(diào)用我們的用例執(zhí)行文件caserunner_myhtml.py
蝴罪,從而達(dá)到接口調(diào)用的效果董济。
通常我們
Flask
項(xiàng)目的入口放在默認(rèn)的app.py
文件中,這個(gè)文件名稱不是固定的要门,可以進(jìn)行自定義以便不同服務(wù)應(yīng)用接口的區(qū)分虏肾。
@app.route('/runallcase', methods=['GET'])
def runallcase():
"""
執(zhí)行所有測試用例接口
:return:
"""
"""調(diào)用CaseRunner中的runall()方法"""
CaseRunner().runall()
return 'Success'
@app.route('/runallcase_bycaselist', methods=['POST'])
def runallcase_bycaselist():
"""
根據(jù)傳入的接口名稱執(zhí)行所有測試用例接口
:return:
"""
"""1. 獲取接口請求post的請求報(bào)文信息,并處理為json格式"""
request_json = request.json
"""2. 獲取請求參數(shù)中的caselist參數(shù)信息"""
caselist = request_json['caselist']
"""3. 調(diào)用CaseRunner中的runall_bycaselist()方法"""
CaseRunner().runall_bycaselist(caselist)
return 'Success'
postman請求效果
五欢搜、最終實(shí)現(xiàn)效果
通過以上一頓操作后封豪,我們來看看最終實(shí)現(xiàn)的效果圖
1. 測試報(bào)告郵件中的內(nèi)容
郵件內(nèi)容包括測試結(jié)果的預(yù)覽信息,附件中報(bào)告了生成的
*.html
炒瘟、*.log
文件
2. 生成的html
測試報(bào)告內(nèi)容
附件中的
*.html
文件為整個(gè)測試用例執(zhí)行后的結(jié)果信息吹埠,包含了測試人員、開始時(shí)間疮装、執(zhí)行耗時(shí)等信息
還可以通過點(diǎn)擊詳細(xì)按鈕查看錯誤詳情
3. 生成的log
日志文件內(nèi)容
總結(jié)
???????以上就是我們使用Python
和 Flask
框架搭配Unittest實(shí)現(xiàn)的一個(gè)接口自動化測試框架缘琅,我將在接下來的章節(jié)中,針對該項(xiàng)目中涉及到的一些類庫使用做相應(yīng)的介紹斩个。
占坑
支線文章
- 《使用Pycharm創(chuàng)建Flask項(xiàng)目》
- 《配置文件的讀寫》
- 待定
- 待定