手把手教你用Python實(shí)現(xiàn)接口自動化測試-開篇

???????本文是《手把手教你用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)接口自動化測試蜈漓?

首先穆桂,我們先看一下正常的接口測試流程是什么?

常規(guī)測試流程

???????這其中可以實(shí)現(xiàn)接口測試的工具有很多融虽,例如:如postman享完、jmeterfiddler等等有额,這些工具使用起來非常方便般又,功能也很多。
常用測試工具

那么為什么還要寫代碼實(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ù)源可以是多樣性的


數(shù)據(jù)源多樣性

???????2:多種結(jié)果驗(yàn)證方式


多種結(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版-歌手首頁

QQ音樂PC版歌手列表.jpg

通過簡單的頁面分析,我們可以獲取歌手列表相關(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 周杰倫-熱門歌曲列表接口返回信息
當(dāng)前歌手熱門歌曲列表相關(guān)返回信息

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 周杰倫-專輯列表接口返回信息

當(dāng)前歌手發(fā)表專輯列表相關(guān)信息

QQ音樂PC版-排行榜首頁
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ù)榜排行榜接口返回信息

最后,通過以上簡單的分析局嘁,我們設(shè)定有如下測試需求:

測試用例設(shè)計(jì)

三溉箕、項(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)目結(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文件目錄

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&notice=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目錄下面都有哪些公共方法

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ù)格式。

testdata文件目錄

4. util中放的是一些私有工具類

util中的工具類一般都是針對當(dāng)前項(xiàng)目封裝的一些測試工具類潮峦,對于別的項(xiàng)目可能就不太適用囱皿。
本文中筆者針對excel文件進(jìn)行讀寫封裝了一個(gè)簡單工具類operateexcel.py

util目錄

5. 實(shí)際的測試case文件

????上面我們有看到測試數(shù)據(jù)參數(shù)的設(shè)置,測試數(shù)據(jù)的獲取方式等等忱嘹,但這些都是前置條件嘱腥,而實(shí)際的測試case是什么樣的呢?

我們將測試用例case維護(hù)在testcase文件目錄下

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文件目錄下
testrunner文件目錄

我們可以在caserunner_myhtml.py文件中定制我們的case執(zhí)行方式:

  1. 執(zhí)行所有接口的測試case
  2. 根據(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)告和日志文件信息光稼。

testresult文件目錄

???????到目前為止我們其實(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ū)分虏肾。

aap文件
@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請求效果

使用postman進(jìn)行GET請求

使用postman進(jìn)行POST請求

五欢搜、最終實(shí)現(xiàn)效果

通過以上一頓操作后封豪,我們來看看最終實(shí)現(xiàn)的效果圖

1. 測試報(bào)告郵件中的內(nèi)容

郵件內(nèi)容包括測試結(jié)果的預(yù)覽信息,附件中報(bào)告了生成的*.html炒瘟、*.log文件

測報(bào)告郵件信息

2. 生成的html測試報(bào)告內(nèi)容

附件中的*.html文件為整個(gè)測試用例執(zhí)行后的結(jié)果信息吹埠,包含了測試人員、開始時(shí)間疮装、執(zhí)行耗時(shí)等信息

生成的html測報(bào)告

還可以通過點(diǎn)擊詳細(xì)按鈕查看錯誤詳情

用例驗(yàn)證失敗詳細(xì)信息

3. 生成的log日志文件內(nèi)容

記錄的log日志文件

總結(jié)

???????以上就是我們使用PythonFlask框架搭配Unittest實(shí)現(xiàn)的一個(gè)接口自動化測試框架缘琅,我將在接下來的章節(jié)中,針對該項(xiàng)目中涉及到的一些類庫使用做相應(yīng)的介紹斩个。

占坑

支線文章

  1. 《使用Pycharm創(chuàng)建Flask項(xiàng)目》
  2. 《配置文件的讀寫》
  3. 待定
  4. 待定
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胯杭,一起剝皮案震驚了整個(gè)濱河市驯杜,隨后出現(xiàn)的幾起案子受啥,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滚局,死亡現(xiàn)場離奇詭異居暖,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)藤肢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門太闺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嘁圈,你說我怎么就攤上這事省骂。” “怎么了最住?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵钞澳,是天一觀的道長。 經(jīng)常有香客問我涨缚,道長轧粟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任脓魏,我火速辦了婚禮兰吟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茂翔。我一直安慰自己混蔼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布珊燎。 她就那樣靜靜地躺著拄丰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪俐末。 梳的紋絲不亂的頭發(fā)上料按,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機(jī)與錄音卓箫,去河邊找鬼载矿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛烹卒,可吹牛的內(nèi)容都是我干的闷盔。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼旅急,長吁一口氣:“原來是場噩夢啊……” “哼逢勾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起藐吮,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤溺拱,失蹤者是張志新(化名)和其女友劉穎逃贝,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迫摔,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沐扳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了句占。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沪摄。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖纱烘,靈堂內(nèi)的尸體忽然破棺而出杨拐,到底是詐尸還是另有隱情,我是刑警寧澤擂啥,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布戏阅,位于F島的核電站,受9級特大地震影響啤它,放射性物質(zhì)發(fā)生泄漏奕筐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一变骡、第九天 我趴在偏房一處隱蔽的房頂上張望离赫。 院中可真熱鬧,春花似錦塌碌、人聲如沸渊胸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翎猛。三九已至,卻和暖如春接剩,著一層夾襖步出監(jiān)牢的瞬間切厘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工懊缺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疫稿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓鹃两,卻偏偏與公主長得像遗座,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子俊扳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容