python3接口自動化測試框架:python3+requests+數據驅動(json)

接口測試是單元測試的一個子集,但又不等同於單元測試。從測試的角度
來看,接口測試的價值在於其測試投入比單元測試少,並且技術難度也比單元測
試小。通常來講,接口測試的粒度要比單元測試更粗,它主要是基於子系統或者
子模塊的接口層面的測試。所以,接口測試須要測試的接口或者函數的數量會遠
遠小於單元測試,與此同時,接口定義的穩定性會遠遠高於類級別的函數。因此,
接口測試用例代碼的改動量也遠遠小於單元測試,代碼維護成本會比單元測試少
不少,於是測試的投入量會小不少。從另一個層面來看,藉助於接口測試,可
以保證子系統或子模塊在各類應用場景下接口調用的正確性,那麼子系統或子模
塊的產品質量也能夠獲得充分的保證。所以,接口測試是一種適度的白盒測試技
術,準確說它是一種灰盒測試,投入產出是很是理想的。
總的來講,接口測試是保證高複雜性系統質量的內在要求和低成本的經
濟利益的驅動做用下的最佳解決方案。主要體如今下面的二個方面:
首先,接口測試節省了測試成本。
其次,接口測試不一樣於傳統開發的單元測試,接口測試是站在用戶的角
度對系統接口進行全面高效持續的檢測。html

(ps:以上有網絡搜索和本身的總結)python

 

好了,話很少說,接下來咱們測試接口的總體思路是這樣的:json

一、把接口的相關數據保存在json文件中。api

二、咱們經過去讀這個json文件,來讀取接口的相關信息,包括:路徑、參數、請求方式、比對值等。服務器

三、基於requests封裝一個發送請求的方法。網絡

四、使用裝飾器來進行具體的測試。函數

 

 

 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文件的格式,一條這樣的數據,表明一條用例:post

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文件取相應的文件名,那麼此處的類就是把這個文件名初始化,而後讀取此文件相關的一些數據。)

(注:一、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:一、IniHelper是封裝的一個讀取配置文件的類。

  二、此處只封裝了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的方法。

(注:一、json裏面的assert的數據至少一條,有可能多條。二、使用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上使用裝飾器,而後裝飾器有二個參數,這裏說明一下:一、就是此case對應的文件名。二、就是此case在json文件中對應的標識。

 

 

建議:

一、每個接口對應一個json文件,而後在這個json文件中爲每一條case添一個標識。(文中的Json文件就是一個接口對應的一條case。)

二、全部的json文件放在同一個文件夾下。

三、每個接口對應一個測試文件。

四、結果最後採用htmltestrunner的html報告輸出。

五、把報告經過email發送。

六、使用jenkins在服務器部署。

 

歡迎你們指證!!!

相關文章
相關標籤/搜索