接口測試是單元測試的一個子集,但又不等同于單元測試。從測試的角度
來看,接口測試的價值在于其測試投入比單元測試少,而且技術難度也比單元測
試小。一般來說,接口測試的粒度要比單元測試更粗,它主要是基于子系統或者
子子產品的接口層面的測試。是以,接口測試需要測試的接口或者函數的數量會遠
遠小于單元測試,與此同時,接口定義的穩定性會遠遠高于類級别的函數。是以,
接口測試用例代碼的改動量也遠遠小于單元測試,代碼維護成本會比單元測試少
很多,因而測試的投入量會小很多。從另外一個層面來看,借助于接口測試,可
以保證子系統或子子產品在各種應用場景下接口調用的正确性,那麼子系統或子模
塊的産品品質也可以得到充分的保證。是以,接口測試是一種适度的白盒測試技
術,準确說它是一種灰盒測試,投入産出是非常理想的。
總的來說,接口測試是保證高複雜性系統品質的内在要求和低成本的經
濟利益的驅動作用下的最佳解決方案。主要展現在下面的二個方面:
首先,接口測試節省了測試成本。
其次,接口測試不同于傳統開發的單元測試,接口測試是站在使用者的角
度對系統接口進行全面高效持續的檢測。
(ps:以上有網絡搜尋和自己的總結)
好了,話不多說,接下來我們測試接口的整體思路是這樣的:
1、把接口的相關資料儲存在json檔案中。
2、我們通過去讀這個json檔案,來讀取接口的相關資訊,包括:路徑、參數、請求方式、比對值等。
3、基于requests封裝一個發送請求的方法。
4、使用裝飾器來進行具體的測試。
1 {
2 "test_1_ip_api": {
3 "url": "http://httpbin.org/ip",
4 "assert": {
5 "origin":"183.16.188.172"
6 },
7 "method": "get",
8 "params": {
9 "a":"b"
10 },
11 "case": "測試httpbin的ip接口傳回正常"
12 }
13 }
以上就是Json檔案的格式,一條這樣的資料,代表一條用例:
test_1_ip_api:算作是一個辨別。
url:接口的路徑。
assert:最後接口的比對值。
method:接口請求方式。
params:請求參數。ps:如果請求方式為post此處為data。
case:此條用例的名字,也就是測試的點。
(注:有些可能需要添加headers,這個使用者自己添加一下就行了,但是後面的代碼稍微修改一下。)
當然有了檔案,那麼我們就需要把這個資料給讀出來。見如下代碼。
class ReadCaseData(object):
def __init__(self,filename):
self.filename = filename
self.path = os.path.join(get_super_path(),'data',self.filename)
@property
def read_case_json(self) -> dict:
'''
擷取指定檔案的json資料
:return:
'''
try:
my_json = open(self.path,encoding='utf-8')
json_data = json.load(my_json)
return json_data
except Exception as err:
print(str(err))
def get_case_content(self,first_key,second_key):
'''
擷取json相應值
'''
return self.read_case_json[first_key][second_key]
def get_assert_keys(self,first_key):
'''
根據用例名取assert的keys
'''
return self.get_case_content(first_key,'assert').keys()
def get_assert_value(self,first_key,assert_key):
'''
取assert的具體值
'''
return self.read_case_json[first_key]['assert'][assert_key]
def get_case_name(self,first_key):
'''
擷取用例名
'''
return self.get_case_content(first_key,'case')
以上就是讀取json檔案的各種資料,并根據需要封裝了一些方法。(思路:會根據不同的json檔案資料,給這個json檔案取相應的檔案名,那麼此處的類就是把這個檔案名初始化,然後讀取此檔案相關的一些資料。)
(注:1、get_super_path()是寫的一個擷取根目錄的方法。)
那麼資料讀出來了,要怎麼運用呢,那麼我們就需要借用一下requests(這個庫應該不用說了,您如果在找這樣的文章,那麼我肯定知道這個庫羅。)。
def get_base_url():
if IniHelper('server.ini').get_value('server', 'select') == 'test':
return IniHelper('server.ini').get_value('server', 'test')
elif IniHelper('server.ini').get_value('server', 'select') == 'formal':
return IniHelper('server.ini').get_value('server', 'formal')
else:
raise AttributeError("配制檔案讀取出錯!請檢查!")
class Myrequests(ReadCaseData):
def __init__(self, filename, case_name):
ReadCaseData.__init__(self, filename)
self.case_name = case_name
self.base_url = get_base_url()
def make_requests_template(self):
'''
根據讀取到的json檔案中的method,來發送不到的請求,目前隻能發送get和post請求
:return:
'''
if self.get_case_content(self.case_name, 'method').lower() == 'get':
body = {}
body['url'] = self.base_url + self.get_case_content(self.case_name, 'url')
body['params'] = self.get_case_content(self.case_name, 'params')
return self.get(**body)
elif self.get_case_content(self.case_name, 'method').lower() == 'post':
body = {}
body['url'] = self.base_url + self.get_case_content(self.case_name, 'url')
body['params'] = self.get_case_content(self.case_name, 'data')
return self.post(**body)
else:
raise AttributeError("錯誤的請求方法, 請檢查配置檔案中的請求方法, 目前隻支援['GET', 'POST']")
def get(self, **kw):
'''
使用requests發送get請求
:param kw: 參數需要傳一個字典表
:return:
'''
return requests.get(**kw)
def post(self, **kw):
'''
使用requests發送post請求
:param kw:參數需要傳一個字典表
:return:
'''
return requests.post(**kw)
@property
def get_json(self):
'''
傳回接口的json資料
:return:
'''
try:
return self.make_requests_template().json()
except Exception as e:
print('json format error' + str(e))
@property
def get_status_code(self):
'''
傳回接口發送後的status_code值
:return:
'''
return self.make_requests_template().status_code
這裡首先是繼承了我們剛剛封裝的讀取的json檔案的類,因為繼承過後就可以使用他的一些方法,然後通過讀取裡面的資料來發送請求等。
注:我這裡的接口的伺服器位址是通過讀取配置檔案裡的,這個代碼就不分享了,大家網找一下,很多。(随意啦)
ps:1、IniHelper是封裝的一個讀取配置檔案的類。
2、此處隻封裝了get和post,當然也可以繼續添加其它(比如:put、delete等等!!)
資料也讀出來了,發送請求的方法也封裝好了,那麼接下來要怎麼用這些資料來測試呢?
def test_case_run(data_file_name, test_case_key):
def _test_case_run(func):
def wrap(self):
r = Myrequests(filename=data_file_name, case_name=test_case_key)
self.r = r
self._testMethodDoc = r.get_case_name(test_case_key)
self.status_code = r.get_status_code
self.json = r.get_json
self.assert_key = r.get_assert_keys(test_case_key)
log.get_log(test_case_key).info(f'開始測試:{test_case_key}')
log.get_log(test_case_key).info('比對:status_code')
self.assertEqual(r.get_status_code, 200)
for key in r.get_assert_keys(test_case_key):
log.get_log(test_case_key).info(f'比對:{key}')
self.assertEqual(get_dict_value(key, **r.get_json), r.get_assert_value(test_case_key, key))
func(self)
return wrap
return _test_case_run
以上就是根據讀取的資料和發送請求的方法封裝的一個裝飾器。
其中:
log:這個是基于logging封裝的記錄log的類。
get_assert_value():這個是寫的一個根據json資料裡讀出來的assert的資料裡面的Key,來擷取實際接口裡面傳回的value的方法。
(注:1、json裡面的assert的資料至少一條,有可能多條。2、使用Key從實際結果中擷取value時,可能是多級字典,是以此方法使用了遞歸)
最後就是我們使用python的unittest來進行測試了。
from src.testcase.method.base_test import BaseTest
from src.testcase.method import wraps
import unittest
class TestApi(BaseTest):
@wraps.test_case_run('data.json', 'test_1_ip_api')
def test_01(self):
self._testMethodDoc = self._testMethodDoc
@wraps.test_case_run('data.json', 'test_2_headers_api')
def test_02(self):
self._testMethodDoc = self._testMethodDoc
@wraps.test_case_run('data.json', 'test_3_post_api')
def test_03(self):
self._testMethodDoc = self._testMethodDoc
if __name__ == '__main__':
unittest.main(verbosity=2)
以上就是實際具體的用例,我們在每一條case上使用裝飾器,然後裝飾器有二個參數,這裡說明一下:1、就是此case對應的檔案名。2、就是此case在json檔案中對應的辨別。
建議:
1、每一個接口對應一個json檔案,然後在這個json檔案中為每一條case添一個辨別。(文中的Json檔案就是一個接口對應的一條case。)
2、所有的json檔案放在同一個檔案夾下。
3、每一個接口對應一個測試檔案。
4、結果最後采用htmltestrunner的html報告輸出。
5、把報告通過email發送。
6、使用jenkins在伺服器部署。
歡迎大家指證!!!
轉載于:https://www.cnblogs.com/Alin-2016/p/8891471.html