搭建支持RESTful風格和WebSocker協(xié)議的接口自動化測試框架

第一步寿羞,你要建立一個叫做 common.py 的公共的方法類。下面我給出的這段注釋詳細的代碼,就是類似我們使用 Postman 的公共方法的封裝,它可以完成 HTTP 協(xié)議的 GET 請求或 POST 請求的驗證慨灭,并且和你的業(yè)務(wù)無關(guān)。

# 定義一個common的類球及,它的父類是object

class Common(object):

? # common的構(gòu)造函數(shù)

? def __init__(self):

? ? # 被測系統(tǒng)的根路由

? ? self.url_root = 'http://127.0.0.1:12356'

? # 封裝你自己的get請求氧骤,uri是訪問路由,params是get請求的參數(shù)吃引,如果沒有默認為空

? def get(self, uri, params=''):

? ? # 拼湊訪問地址

? ? url = self.url_root + uri + params

? ? # 通過get請求訪問對應(yīng)地址

? ? res = requests.get(url)

? ? # 返回request的Response結(jié)果筹陵,類型為requests的Response類型

? ? return res

? # 封裝你自己的post方法,uri是訪問路由镊尺,params是post請求需要傳遞的參數(shù)朦佩,如果沒有參數(shù)這里為空

? def post(self, uri, params=''):

? ? # 拼湊訪問地址

? ? url = self.url_root + uri

? ? if len(params) > 0:

? ? ? # 如果有參數(shù),那么通過post方式訪問對應(yīng)的url庐氮,并將參數(shù)賦值給requests.post默認參數(shù)data

? ? ? # 返回request的Response結(jié)果语稠,類型為requests的Response類型

? ? ? res = requests.post(url, data=params)

? ? else:

? ? ? # 如果無參數(shù),訪問方式如下

? ? ? # 返回request的Response結(jié)果弄砍,類型為requests的Response類型

? ? ? res = requests.post(url)

? ? return res

接下來仙畦,用你自己的 Common 類,修改第一個接口的單接口測試腳本音婶,就可以得到下面的代碼了慨畸。

# Python代碼中引入requests庫,引入后才可以在你的代碼中使用對應(yīng)的類以及成員函數(shù)

from common import Common

# 首頁的路由

uri = '/'

# 實例化自己的Common

comm = Common()

#調(diào)用你自己在Common封裝的get方法 桃熄,返回結(jié)果存到了response_index中

response_index = comm.get(uri)

# 存儲返回的response_index對象的text屬性存儲了訪問主頁的response信息先口,通過下面打印出來

print('Response內(nèi)容:' + response_index.text)

從這段代碼中你可以看到,與前面對應(yīng)的單接口測試腳本相比瞳收,代碼的行數(shù)有明顯的減少碉京,這也能減少你很多的工作量,與此同時螟深,如果你有任何關(guān)于 HTTP 協(xié)議的操作谐宙,都可以在 Common 類中進行修改和完善。

如果使用你自己剛剛建立的公共類(在我們內(nèi)部有時候喜歡把它叫做輪子界弧,這是源于一句俚語“不用重復(fù)造輪子”凡蜻,因為 Common 類就是重復(fù)被各個檢測代碼使用的“輪子”)修改一下第二個接口的單接口測試腳本,代碼就會變成下面這個樣子:

#登錄頁路由

uri = '/login'

# username變量存儲用戶名參數(shù)

username = 'criss'

# password變量存儲密碼參數(shù)

password = 'criss'

# 拼湊body的參數(shù)

payload = 'username=' + username + '&password=' + password

comm = Common()

response_login = comm.post(uri,params=payload)

print('Response內(nèi)容:' + response_login.text)

當你有一些更加復(fù)雜的腳本時垢箕,你會發(fā)現(xiàn)兩次代碼的變化會變得更明顯划栓,也更易讀。

那么条获。使用我們一起封裝的框架來完成上面的多接口測試后忠荞,就會得到下面的代碼:

# Python代碼中引入requests庫,引入后才可以在你的代碼中使用對應(yīng)的類以及成員函數(shù)

from common import Common

# 建立uri_index的變量,存儲戰(zhàn)場的首頁路由

uri_index = '/'

# 實例化自己的Common

comm = Common()

#調(diào)用你自己在Common封裝的get方法 委煤,返回結(jié)果存到了response_index中

response_index = comm.get(uri_index)

# 存儲返回的response_index對象的text屬性存儲了訪問主頁的response信息堂油,通過下面打印出來

print('Response內(nèi)容:' + response_index.text)

# uri_login存儲戰(zhàn)場的登錄

uri_login = '/login'

# username變量存儲用戶名參數(shù)

username = 'criss'

# password變量存儲密碼參數(shù)

password = 'criss'

# 拼湊body的參數(shù)

payload = 'username=' + username + '&password=' + password

comm = Common()

response_login = comm.post(uri_login,params=payload)

print('Response內(nèi)容:' + response_login.text)

# uri_selectEq存儲戰(zhàn)場的選擇武器

uri_selectEq = '/selectEq'

# 武器編號變量存儲用戶名參數(shù)

equipmentid = '10003'

# 拼湊body的參數(shù)

payload = 'equipmentid=' + equipmentid

comm = Common()

response_selectEq = comm.post(uri_selectEq,params=payload)

print('Response內(nèi)容:' + response_selectEq.text)

# uri_kill存儲戰(zhàn)場的選擇武器

uri_kill = '/kill'

# 武器編號變量存儲用戶名參數(shù)

enemyid = '20001'

# 拼湊body的參數(shù)

payload = 'enemyid=' + enemyid+"&equipmentid="+equipmentid

comm = Common()

response_kill = comm.post(uri_kill,params=payload)

print('Response內(nèi)容:' + response_kill.text)

你可以看到,上面的代碼大量重復(fù)了你自己寫的通用類的調(diào)用碧绞,這個其實是可以合成一個的府框;同時,你再觀察一下我們一起寫的 Common 類讥邻,你會發(fā)現(xiàn)有一個 self.url_root = ‘http://127.0.0.1:12356’迫靖,如果這里這樣寫,你的 Common 就只能用來測試我們這個小系統(tǒng)了计维,除非你每次都去修改框架袜香。

但是,任何一個框架的維護者鲫惶,都不希望框架和具體邏輯強相關(guān)蜈首,因此這也是一個優(yōu)化點,那么將上面的內(nèi)容都修改后欠母,代碼就會變成下面這個樣子:

# Python代碼中引入requests庫欢策,引入后才可以在你的代碼中使用對應(yīng)的類以及成員函數(shù)

from common import Common

# 建立uri_index的變量,存儲戰(zhàn)場的首頁路由

uri_index = '/'

# 實例化自己的Common

comm = Common('http://127.0.0.1:12356')

#調(diào)用你自己在Common封裝的get方法 赏淌,返回結(jié)果存到了response_index中

response_index = comm.get(uri_index)

# 存儲返回的response_index對象的text屬性存儲了訪問主頁的response信息踩寇,通過下面打印出來

print('Response內(nèi)容:' + response_index.text)

# uri_login存儲戰(zhàn)場的登錄

uri_login = '/login'

# username變量存儲用戶名參數(shù)

username = 'criss'

# password變量存儲密碼參數(shù)

password = 'criss'

# 拼湊body的參數(shù)

payload = 'username=' + username + '&password=' + password

response_login = comm.post(uri_login,params=payload)

print('Response內(nèi)容:' + response_login.text)

# uri_selectEq存儲戰(zhàn)場的選擇武器

uri_selectEq = '/selectEq'

# 武器編號變量存儲用戶名參數(shù)

equipmentid = '10003'

# 拼湊body的參數(shù)

payload = 'equipmentid=' + equipmentid

response_selectEq = comm.post(uri_selectEq,params=payload)

print('Response內(nèi)容:' + response_selectEq.text)

# uri_kill存儲戰(zhàn)場的選擇武器

uri_kill = '/kill'

# 武器編號變量存儲用戶名參數(shù)

enemyid = '20001'

# 拼湊body的參數(shù)

payload = 'enemyid=' + enemyid+"&equipmentid="+equipmentid

response_kill = comm.post(uri_kill,params=payload)

print('Response內(nèi)容:' + response_kill.text)

是不是比上一個節(jié)省了很多代碼,同時也看的更加的易讀了六水,那么我們封住好的Common就變成了如下的樣子:

# 定義一個common的類俺孙,它的父類是object

class Common(object):

# common的構(gòu)造函數(shù)

def __init__(self,url_root):

# 被測系統(tǒng)的跟路由

self.url_root = url_root

# 封裝你自己的get請求,uri是訪問路由掷贾,params是get請求的參數(shù)睛榄,如果沒有默認為空

def get(self, uri, params=''):

# 拼湊訪問地址

url = self.url_root + uri + params

# 通過get請求訪問對應(yīng)地址

res = requests.get(url)

# 返回request的Response結(jié)果,類型為requests的Response類型

return res

# 封裝你自己的post方法想帅,uri是訪問路由场靴,params是post請求需要傳遞的參數(shù),如果沒有參數(shù)這里為空

def post(self, uri, params=''):

# 拼湊訪問地址

url = self.url_root + uri

if len(params) > 0:

# 如果有參數(shù)港准,那么通過post方式訪問對應(yīng)的url旨剥,并將參數(shù)賦值給requests.post默認參數(shù)data

# 返回request的Response結(jié)果,類型為requests的Response類型

res = requests.post(url, data=params)

else:

# 如果無參數(shù)浅缸,訪問方式如下

# 返回request的Response結(jié)果轨帜,類型為requests的Response類型

res = req

你可以看到,在上面這段代碼中衩椒,我主要是讓我們 Common 類的構(gòu)造函數(shù)接受了一個變量阵谚,這個變量就是被測系統(tǒng)的根路由蚕礼。這樣是不是就比上一個代碼段節(jié)省了很多代碼烟具,同時也更加易讀了梢什?那么我們封裝好的 Common 就變成了下面這個樣子:

# 定義一個common的類,它的父類是object

class Common(object):

? # common的構(gòu)造函數(shù)

? def __init__(self,url_root):

? ? # 被測系統(tǒng)的跟路由

? ? self.url_root = url_root

? # 封裝你自己的get請求朝聋,uri是訪問路由嗡午,params是get請求的參數(shù),如果沒有默認為空

? def get(self, uri, params=''):

? ? # 拼湊訪問地址

? ? url = self.url_root + uri + params

? ? # 通過get請求訪問對應(yīng)地址

? ? res = requests.get(url)

? ? # 返回request的Response結(jié)果冀痕,類型為requests的Response類型

? ? return res

? # 封裝你自己的post方法斋配,uri是訪問路由刹碾,params是post請求需要傳遞的參數(shù),如果沒有參數(shù)這里為空

? def post(self, uri, params=''):?

? ? # 拼湊訪問地址?

? ? url = self.url_root + uri?

? ? if len(params) > 0:?

? ? ? # 如果有參數(shù),那么通過post方式訪問對應(yīng)的url该园,并將參數(shù)賦值給requests.post默認參數(shù)data

? ? ? # 返回request的Response結(jié)果,類型為requests的Response類型

? ? ? res = requests.post(url, data=params)?

? ? else:

? ? ? # 如果無參數(shù)鹿蜀,訪問方式如下

? ? ? # 返回request的Response結(jié)果庵佣,類型為requests的Response類型

? ? ? res = requests.post(url)

? ? ? return res

通過改造 Common 類的構(gòu)造函數(shù),這個類已經(jīng)變成一個通用類了婿斥,無論是哪一個項目的接口測試劝篷,都可以使用它來完成 HTTP 協(xié)議的接口驗證了。其實到這里民宿,我們上面說的只能算是一個調(diào)試代碼娇妓,還不能算是一個測試框架。上面這些代碼所有的返回值都打印到控制臺后活鹰,為了完成接口測試哈恰,你需要時時刻刻看著控制臺,這還不能算是自動化志群,只能說是一個輔助小工具着绷。

在這里,你應(yīng)該讓全部測試結(jié)果都存儲到測試報告里面赖舟,同時通過一個測試驅(qū)動框架來完成各個模塊的驅(qū)動蓬戚,比如Python 的 Unittest 。因此宾抓,上面的 Common 類還需要和 Python 的 unittest 一起使用子漩,才算是一個完美的測試框架。


讓你的框架支持RESTful風格的接口

RESTful 接口的測試和原始的 HTTP 協(xié)議接口的測試石洗,又有什么區(qū)別呢幢泼?這里面有兩部分需要你特別關(guān)注:數(shù)據(jù)交換的承載方式和操作方式。

我先說說數(shù)據(jù)交換的承載方式讲衫,RESTful 風格的接口主要是以 JSON 格式來進行數(shù)據(jù)交換缕棵。

另外一個部分是操作方式孵班,上面用了HTTP 協(xié)議的 Get 和 Post,其實 HTTP 協(xié)議有很多方法招驴,但是我們僅僅用了這兩種篙程,而 RESTful 的規(guī)定,使 HTTP 的很多方法都被利用到了别厘,比如說虱饿,Get 方法用來獲取資源,Post 方法用來新建資源(或者更新資源)触趴;再比如說氮发,Put 方法用來更新資源、Delete 方法用來刪除資源等等冗懦。

現(xiàn)在爽冕,我們已經(jīng)可以借助開源庫,解決數(shù)據(jù)交換的事情了披蕉,但是颈畸,RESTful 風格接口和普通 HTTP 接口相比,還有一個明顯的區(qū)別嚣艇,那就是 RESTful 規(guī)定了 HTTP 的每一個方法都做固定的事情承冰,可我們原來框架中的 Common 類卻只支持 Get 和 Post 方法,因此食零,你需要在 Common 類中加入 Delete 和 Put 方法的支持困乒。具體的操作你可以依據(jù)下面這個代碼段來完成:

? def put(self,uri,params=None):

? ? '''

? ? 封裝你自己的put方法,uri是訪問路由贰谣,params是put請求需要傳遞的參數(shù)娜搂,如果沒有參數(shù)這里為空

? ? :param uri: 訪問路由?

? ? :param params: 傳遞參數(shù),string類型吱抚,默認為None?

? ? :return: 此次訪問的response

? ? '''?

? ? url = self.url_root+uri

? ? if params is not None:

? ? ? # 如果有參數(shù)百宇,那么通過put方式訪問對應(yīng)的url,并將參數(shù)賦值給requests.put默認參數(shù)data

? ? ? # 返回request的Response結(jié)果秘豹,類型為requests的Response類型

? ? ? res = requests.put(url, data=params)

? else:


? ? ? # 如果無參數(shù)携御,訪問方式如下


? ? ? # 返回request的Response結(jié)果,類型為requests的Response類型


? ? ? res = requests.put(url)


? return res

def delete(self,uri,params=None):

? '''

? 封裝你自己的delete方法既绕,uri是訪問路由啄刹,params是delete請求需要傳遞的參數(shù),如果沒有參數(shù)這里為空

? :param uri: 訪問路由

? :param params: 傳遞參數(shù)凄贩,string類型誓军,默認為None

? :return: 此次訪問的response

? '''

? url = self.url_root + uri

? if params is not None:

? ? # 如果有參數(shù),那么通過delete方式訪問對應(yīng)的url疲扎,并將參數(shù)賦值給requests.delete默認參數(shù)data

? ? # 返回request的Response結(jié)果昵时,類型為requests的Response類型

? ? res = requests.delete(url, data=params)

? else:

? ? # 如果無參數(shù)捷雕,訪問方式如下

? ? # 返回request的Response結(jié)果,類型為requests的Response類型

? ? res = requests.delete(url)

? return res

在上面的代碼中壹甥,你可以看到救巷,我們?yōu)榱藢崿F(xiàn) HTTP 協(xié)議的 Put 和 Delete 方法,自己封裝了 put() 函數(shù)和 delete() 函數(shù)盹廷。其實征绸,要實現(xiàn) RESTful 風格的接口測試,你只要封裝 HTTP 協(xié)議對應(yīng)的 Method 方法就可以了俄占,這樣,你的框架就能完美的支持 RESTful 風格的接口了淆衷。完成了這個操作后缸榄,我們的 Common 類就既可以完成 HTTP 協(xié)議接口的測試,也可以完成 RESTful 接口的測試了祝拯。


將 WebSocket 接口封裝進你的框架

庫甚带,因此我只要用它完成客戶端的撰寫,就可以進行接口測試了佳头。這里鹰贵,我寫下了第一個 WebSocket 的調(diào)用代碼(這里我們以 http://www.websocket.org/demos/echo/ 為例),如下面圖中所示康嘉,我在代碼里面寫了詳細的注釋碉输,你肯定能看懂每一句話的意思。

#引入websocket的create_connection類

from websocket import create_connection

# 建立和WebSocket接口的鏈接

ws = create_connection("ws://echo.websocket.org")

# 打印日子

print("發(fā)送 'Hello, World'...")

# 發(fā)送Hello亭珍,World

ws.send("Hello, World")

# 將WebSocket的返回值存儲result變量

result = ws.recv()

# 打印返回的result

print("返回"+result)

# 關(guān)閉WebSocket鏈接

ws.close()

不知道你發(fā)現(xiàn)沒有敷钾,上面的代碼和 HTTP 協(xié)議的接口類似,都是先和一個請求建立連接肄梨,然后發(fā)送信息阻荒。它們的區(qū)別是,WebSocket 是一個長連接众羡,因此需要人為的建立連接侨赡,然后再關(guān)閉鏈接,而 HTTP 卻并不需要進行這一操作粱侣。

我們上面封裝了 Common 類羊壹,你可以在它的構(gòu)造函數(shù)中,添加一個 API 類型的參數(shù)甜害,以便于知道自己要做的是什么協(xié)議的接口舶掖,其中 http 代表 HTTP 協(xié)議接口,ws 代表 WebSocket 協(xié)議接口尔店。由于 WebSocket 是一個長連接眨攘,我們在 Common 類析構(gòu)函數(shù)中添加了關(guān)閉 ws 鏈接的代碼主慰,以釋放 WebSocket 長連接。依據(jù)前面的交互流程鲫售,實現(xiàn)代碼如下所示:

#!/usr/bin/env python

# -*- coding: utf-8 -*-

# python代碼中引入requests庫共螺,引入后才可以在你的代碼中使用對應(yīng)的類以及成員函數(shù)

import requests

from websocket import create_connection

# 定義一個common的類,它的父類是object

class Common(object):

? # common的構(gòu)造函數(shù)

? def __init__(self,url_root,api_type):

? ? '''

? ? :param api_type:接口類似當前支持http情竹、ws藐不,http就是HTTP協(xié)議,ws是WebSocket協(xié)議

? ? :param url_root: 被測系統(tǒng)的根路由

? ? '''?

? ? if api_type=='ws':

? ? ? self.ws = create_connection(url_root)

? ? elif api_type=='http':

? ? ? self.ws='null'

? ? ? self.url_root = url_root

? # ws協(xié)議的消息發(fā)送


? def send(self,params):

? ? '''

? ? :param params: websocket接口的參數(shù)


? ? :return: 訪問接口的返回值

? ? '''

? ? self.ws.send(params)

? ? res = self.ws.recv()

? ? return res

? # common類的析構(gòu)函數(shù)秦效,清理沒有用的資源


? def __del__(self):

? ? '''

? ? :return:

? ? '''

? ? if self.ws!='null":

? ? ? self.ws.close()

? def get(self, uri, params=None):

? ? '''

? ? 封裝你自己的get請求雏蛮,uri是訪問路由,params是get請求的參數(shù)阱州,如果沒有默認為空

? ? :param uri: 訪問路由

? ? :param params: 傳遞參數(shù)挑秉,string類型,默認為None

? ? :return: 此次訪問的response

? ? '''

? ? # 拼湊訪問地址

? ? if params is not None:

? ? ? url = self.url_root + uri + params

? ? else:?

? ? ? url = self.url_root + uri

? ? # 通過get請求訪問對應(yīng)地址

? ? res = requests.get(url)

? ? # 返回request的Response結(jié)果苔货,類型為requests的Response類型

? ? return res

? def post(self, uri, params=None):

? ? '''

? ? 封裝你自己的post方法犀概,uri是訪問路由,params是post請求需要傳遞的參數(shù)夜惭,如果沒有參數(shù)這里為空

? ? :param uri: 訪問路由

? ? :param params: 傳遞參數(shù)姻灶,string類型,默認為None

? ? :return: 此次訪問的response

? ? '''

? ? # 拼湊訪問地址

? ? url = self.url_root + uri

? ? if params is not None:

? ? ? # 如果有參數(shù)诈茧,那么通過post方式訪問對應(yīng)的url产喉,并將參數(shù)賦值給requests.post默認參數(shù)data

? ? ? # 返回request的Response結(jié)果,類型為requests的Response類型

? ? ? res = requests.post(url, data=params)

? ? else:

? ? ? # 如果無參數(shù)若皱,訪問方式如下

? ? ? # 返回request的Response結(jié)果镊叁,類型為requests的Response類型

? ? ? res = requests.post(url)?

? ? return res

? def put(self,uri,params=None):

? ? '''

? ? 封裝你自己的put方法,uri是訪問路由走触,params是put請求需要傳遞的參數(shù)晦譬,如果沒有參數(shù)這里為空

? ? :param uri: 訪問路由

? ? :param params: 傳遞參數(shù),string類型互广,默認為None

? ? :return: 此次訪問的response

? ? '''

? ? url = self.url_root+uri

? ? if params is not None:

? ? ? # 如果有參數(shù)敛腌,那么通過put方式訪問對應(yīng)的url,并將參數(shù)賦值給requests.put默認參數(shù)data

? ? ? # 返回request的Response結(jié)果惫皱,類型為requests的Response類型

? ? ? res = requests.put(url, data=params)

? ? else:

? ? ? # 如果無參數(shù)像樊,訪問方式如下

? ? ? # 返回request的Response結(jié)果,類型為requests的Response類型

? ? ? res = requests.put(url)

? ? return res

? def delete(self,uri,params=None):

? ? '''

? ? 封裝你自己的delete方法旅敷,uri是訪問路由生棍,params是delete請求需要傳遞的參數(shù),如果沒有參數(shù)這里為空

? ? :param uri: 訪問路由

? ? :param params: 傳遞參數(shù)媳谁,string類型涂滴,默認為None

? ? :return: 此次訪問的response

? ? '''

? ? url = self.url_root + uri

? ? if params is not None:

? ? ? # 如果有參數(shù)友酱,那么通過put方式訪問對應(yīng)的url,并將參數(shù)賦值給requests.put默認參數(shù)data

? ? ? # 返回request的Response結(jié)果柔纵,類型為requests的Response類型

? ? ? res = requests.delete(url, data=params)

? ? else:

? ? ? # 如果無參數(shù)缔杉,訪問方式如下

? ? ? # 返回request的Response結(jié)果,類型為requests的Response類型

? ? ? res = requests.put(url)

? ? return res

那么搁料,使用上述的 Common 類將上面那個流水賬一樣的腳本進行改造后或详,就得出了下面這段代碼:

from common import Common

# 建立和WebSocket接口的鏈接

con = Common('ws://echo.websocket.org','ws')

# 獲取返回結(jié)果

result = con.send('Hello, World...')

#打印日志

print(result)

#釋放WebSocket的長連接

del con

現(xiàn)在,從改造后的代碼中郭计,你是不是更能體會到框架的魅力了霸琴?它能讓代碼變得更加簡潔和易讀,將 WebSocket 的協(xié)議封裝到你的框架后拣宏,你就擁有了一個既包含 HTTP 協(xié)議又包含 WebSocket 協(xié)議的接口測試框架了沈贝,隨著你不斷地積累新協(xié)議,你的框架會越來越強大勋乾,你自己的秘密武器庫也會不斷擴充,隨著你對它的不斷完善嗡善,它會讓你的接口測試工作越來越簡單辑莫,越來越快速。


最后罩引,我們需要將數(shù)據(jù)封裝各吨,例如把測試數(shù)據(jù)放在excel里,Excel 是在設(shè)計測試用例方面使用最多的一個工具袁铐,那么我們也就可以用 Excel 作為自己的參數(shù)存儲文件揭蜒。那么如何選取和調(diào)用參數(shù)呢?你可以看看我設(shè)計的參數(shù)類:

import json

import xlrd

class Param(object):

? def __init__(self,paramConf='{}'):

? ? self.paramConf = json.loads(paramConf)

? def paramRowsCount(self):

? ? pass

? def paramColsCount(self):

? ? pass

? def paramHeader(self):

? ? pass

? def paramAllline(self):

? ? pass

? def paramAlllineDict(self):

? ? pass

class XLS(Param):

? '''

? xls基本格式(如果要把xls中存儲的數(shù)字按照文本讀出來的話,純數(shù)字前要加上英文單引號:

? 第一行是參數(shù)的注釋,就是每一行參數(shù)是什么

? 第二行是參數(shù)名,參數(shù)名和對應(yīng)模塊的po頁面的變量名一致

? 第3~N行是參數(shù)

? 最后一列是預(yù)期默認頭Exp

? '''

? def __init__(self, paramConf):

? ? '''

? ? :param paramConf: xls 文件位置(絕對路徑)

? ? '''

? ? self.paramConf = paramConf

? ? self.paramfile = self.paramConf['file']

? ? self.data = xlrd.open_workbook(self.paramfile)

? ? self.getParamSheet(self.paramConf['sheet'])

? def getParamSheet(self,nsheets):

? ? '''

? ? 設(shè)定參數(shù)所處的sheet

? ? :param nsheets: 參數(shù)在第幾個sheet中

? ? :return:

? ? '''

? ? self.paramsheet = self.data.sheets()[nsheets]

? def getOneline(self,nRow):

? ? '''

? ? 返回一行數(shù)據(jù)

? ? :param nRow: 行數(shù)

? ? :return: 一行數(shù)據(jù) []

? ? '''

? ? return self.paramsheet.row_values(nRow)

? def getOneCol(self,nCol):

? ? '''

? ? 返回一列

? ? :param nCol: 列數(shù)

? ? :return: 一列數(shù)據(jù) []

? ? '''

? ? return self.paramsheet.col_values(nCol)

? def paramRowsCount(self):

? ? '''

? ? 獲取參數(shù)文件行數(shù)

? ? :return: 參數(shù)行數(shù) int

? ? '''

? ? return self.paramsheet.nrows

? def paramColsCount(self):

? ? '''

? ? 獲取參數(shù)文件列數(shù)(參數(shù)個數(shù))

? ? :return: 參數(shù)文件列數(shù)(參數(shù)個數(shù)) int

? ? '''

? ? return self.paramsheet.ncols

? def paramHeader(self):

? ? '''

? ? 獲取參數(shù)名稱

? ? :return: 參數(shù)名稱[]

? ? '''

? ? return self.getOneline(1)

? def paramAlllineDict(self):

? ? '''

? ? 獲取全部參數(shù)

? ? :return: {{}},其中dict的key值是header的值

? ? '''

? ? nCountRows = self.paramRowsCount()

? ? nCountCols = self.paramColsCount()

? ? ParamAllListDict = {}

? ? iRowStep = 2

? ? iColStep = 0

? ? ParamHeader= self.paramHeader()

? ? while iRowStep < nCountRows:

? ? ParamOneLinelist=self.getOneline(iRowStep)

? ? ParamOnelineDict = {}

? ? while iColStep<nCountCols:

? ? ParamOnelineDict[ParamHeader[iColStep]]=ParamOneLinelist[iColStep]

? ? iColStep=iColStep+1

? ? iColStep=0

? ? ParamAllListDict[iRowStep-2]=ParamOnelineDict

? ? iRowStep=iRowStep+1

? ? return ParamAllListDict

? def paramAllline(self):

? ? '''? ? 獲取全部參數(shù)

? ? :return: 全部參數(shù)[[]]? '''

? ? nCountRows= self.paramRowsCount()

? ? paramall = []

? ? iRowStep =2

? ? while iRowStep<nCountRows:

? ? paramall.append(self.getOneline(iRowStep))

? ? iRowStep=iRowStep+1

? ? return paramall

? def __getParamCell(self,numberRow,numberCol):

? ? return self.paramsheet.cell_value(numberRow,numberCol)

class ParamFactory(object):

? def chooseParam(self,type,paramConf):

? ? map_ = {

? ? 'xls': XLS(paramConf)

? ? }

? ? return map_[type

上面這個代碼看著很多剔桨,但你不需要完全看得懂屉更,你只需要知道它解決問題的思路和方法就可以了,思路就是通過統(tǒng)一抽象洒缀,建立一個公共處理數(shù)據(jù)的方式瑰谜。你可以設(shè)計和使用簡單工廠類的設(shè)計模式,這樣如果多一種參數(shù)存儲類型树绩,再添加一個對應(yīng)的處理類就可以了萨脑,這很便于你做快速擴展,也可以一勞永逸地提供統(tǒng)一數(shù)據(jù)的處理模式饺饭。

接下來渤早,你就可以把這次測試的全部參數(shù)都存到 Excel 里面了,具體內(nèi)容如下圖所示:

通過上面的參數(shù)類你可以看出瘫俊,在這個 Excel 文件中鹊杖,第一行是給人讀取的每一列參數(shù)的注釋悴灵,而所有的 Excel 都是從第二行開始讀取的,第二行是參數(shù)名和固定的表示預(yù)期結(jié)果的 exp〗鍪纾現(xiàn)在称勋,我們使用 ParamFactory 類,再配合上面的這個 Excel涯竟,就可以完成”戰(zhàn)場“系統(tǒng)“選擇武器”接口的改造了赡鲜,如下面這段代碼所示:

#引入Common、ParamFactory類

from common import Common

from param import ParamFactory

import os

# uri_login存儲戰(zhàn)場的選擇武器

uri_selectEq = '/selectEq'

comm = Common('http://127.0.0.1:12356',api_type='http')

# 武器編號變量存儲武器編號庐船,并且驗證返回時是否有參數(shù)設(shè)計預(yù)期結(jié)果

# 獲取當前路徑絕對值

curPath = os.path.abspath('.')

# 定義存儲參數(shù)的excel文件路徑

searchparamfile = curPath+'/equipmentid_param.xls'

# 調(diào)用參數(shù)類完成參數(shù)讀取银酬,返回是一個字典,包含全部的excel數(shù)據(jù)除去excel的第一行表頭說明

searchparam_dict = ParamFactory().chooseParam('xls',{'file':searchparamfile,'sheet':0}).paramAlllineDict()

i=0

while i<len(searchparam_dict):

? # 讀取通過參數(shù)類獲取的第i行的參數(shù)

? payload = 'equipmentid=' + searchparam_dict[i]['equipmentid']

? # 讀取通過參數(shù)類獲取的第i行的預(yù)期

? exp=searchparam_dict[i]['exp']

? # 進行接口測試

? response_selectEq = comm.post(uri_selectEq,params=payload)

? # 打印返回結(jié)果

? print('Response內(nèi)容:' + response_selectEq.text)

? # 讀取下一行excel中的數(shù)據(jù)

? i=i+1

這樣再執(zhí)行你的測試腳本筐钟,你就可以看到數(shù)據(jù)文件中的三條數(shù)據(jù)揩瞪,已經(jīng)都會順序的自動執(zhí)行了。那么后續(xù)如果將它付諸于你自己的技術(shù)棧篓冲,以及自己的測試驅(qū)動框架比如 Python 的unittest李破,你就可以通過斷言完成預(yù)期結(jié)果的自動驗證了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末壹将,一起剝皮案震驚了整個濱河市嗤攻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌诽俯,老刑警劉巖妇菱,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異暴区,居然都是意外死亡闯团,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門仙粱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來房交,“玉大人,你說我怎么就攤上這事缰盏∮坑” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵口猜,是天一觀的道長负溪。 經(jīng)常有香客問我,道長济炎,這世上最難降的妖魔是什么川抡? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上崖堤,老公的妹妹穿的比我還像新娘侍咱。我一直安慰自己,他們只是感情好密幔,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布楔脯。 她就那樣靜靜地躺著,像睡著了一般胯甩。 火紅的嫁衣襯著肌膚如雪昧廷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天偎箫,我揣著相機與錄音木柬,去河邊找鬼。 笑死淹办,一個胖子當著我的面吹牛眉枕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播怜森,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼速挑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了副硅?” 一聲冷哼從身側(cè)響起梗摇,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎想许,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體断序,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡流纹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了违诗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漱凝。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖诸迟,靈堂內(nèi)的尸體忽然破棺而出茸炒,到底是詐尸還是另有隱情,我是刑警寧澤阵苇,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布壁公,位于F島的核電站,受9級特大地震影響绅项,放射性物質(zhì)發(fā)生泄漏紊册。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一快耿、第九天 我趴在偏房一處隱蔽的房頂上張望囊陡。 院中可真熱鬧芳绩,春花似錦、人聲如沸撞反。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽遏片。三九已至嘹害,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丁稀,已是汗流浹背吼拥。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留线衫,地道東北人凿可。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像授账,于是被迫代替她去往敵國和親枯跑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

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