在編寫接口測試腳本時,要考慮一個問題:參數值從哪里獲取
一種方式是可以通過數據庫來獲取,但是通過這次接口測試,我發現讀取數據庫有一個缺點:速度慢
可能和我的sql寫法有關,有些sql加的約束條件比較少,有時甚至全量查詢,把所有結果遍歷一遍,這樣一輪下來直接就炸了,那速度比蝸牛還慢
這種方式給我的體驗不太好,一方面本身連數據庫這個操作我就不太願意用,生怕對數據庫造成什么傷害......
另一種方式就是寫死參數,不過除非是一些固定的參數,比如按照某個類型查詢,類型是固定的,那么可以事先定義一個列表或字典存放類型值,然后依次遍歷即可;
否則一般不推薦寫死參數,寫死的話拓展性不強,換個測試環境,腳本可能就運行不起來了
還有就是通過接口獲取想要的數據了,也就是一個接口能返回某些參數想要的值,那么就把這個接口的返回值傳遞給下個接口的參數
這樣一來,參數值是動態生成的,即使切換環境,也可以在新環境獲取參數值,然后再去發送請求
本質上接口間傳遞參數,其實就是處理上一個接口的返回數據,抽取出自己想要的某個字段或某一批字段
舉個栗子:
有2個接口,A接口用於查詢所有的標簽數據,B接口需要傳入一個標簽,然后生成一條草稿數據,這樣的話,可以在A接口查詢出的所有標簽中選擇一個傳給B
A接口的返回數據如下
seq表示標簽編碼,B接口本質上就是需要一條標簽編碼來生成數據
labelStatus表示標簽狀態,0表示啟用,1表示未啟用
{ 'total': '5', 'rows': [{ 'seq': '151ceb6c0e624537a2b067d511c4c966', 'labelCode': '004', 'labelName': '拼多多', 'labelStatus': 0, 'kseq': None, 'lseq': None }, { 'seq': '1aa2ddfe896848cf893eebe6c37a79e6', 'labelCode': '002', 'labelName': '京東', 'labelStatus': 0, 'kseq': None, 'lseq': None }, { 'seq': '25879c28e8b54bf0b75168fc60c31a91', 'labelCode': '001', 'labelName': '天貓', 'labelStatus': 0, 'kseq': None, 'lseq': None }, { 'seq': '7715e67a153d484996a07af19ef33c09', 'labelCode': '003', 'labelName': '蘇寧', 'labelStatus': 0, 'kseq': None, 'lseq': None }, { 'seq': '647733588fa34f60858e42ccd7357975', 'labelCode': '005', 'labelName': '唯品會', 'labelStatus': 1, 'kseq': None, 'lseq': None }] }
先寫一個方法,提取查詢到的標簽編碼
def get_all_label(self): """獲取菜單中所有標簽數據""" url = "http://127.0.0.1:8080/XXX" payload = { "page": "1", "rows": "10", "sort": "labelStatus", "order": "asc" } response = self.s.test_login().post(url, data=payload, headers=self.header, verify=False) data = json.loads(response.content) # print(data) try: self.assertIn("rows", data) self.assertIn("total", data) if data["rows"]: labels = [] # 定義一個列表存查詢到的所有標簽數據 for t in data["rows"]: """以列表中嵌套字典的格式保存,易於調用""" if t["labelStatus"] == 0: """如果labelStatus為0則追加到列表中""" labels.append( {"seq": t["seq"], "labelCode": t["labelCode"], "labelName": t["labelName"], "labelStatus": t["labelStatus"]} ) # print(labels) return labels else: labels = None return labels except Exception as e: print("請求url:", response.url) print("傳入參數:", payload) raise e
B接口用於創建草稿數據,參數中用到A接口返回的標簽編碼seq
創建一個生成草稿數據的方法,在這個方法中,定義一個變量seq,用於接收標簽編碼
def add_draft(self, seq=None): """新增草稿""" url = "http://127.0.0.1:8080/XXX" payload = { "title": "XX", "applyType": 0, "hotFlag": 1, "content": "XX", "replyContent": "XX", "labelList[0].lseq": seq, # 接收傳入的seq "faqList[0].content": "XX", "faqList[0].replyContent": "XX", "fnType": 0 } response = self.s.test_login().post(url, data=payload, headers=self.header, verify=False) data = response.json() # print(data) try: self.assertEqual(data["success"], "true") self.assertEqual(data["successful"], True)return data except Exception as e: print("請求url:", response.url) print("傳入參數:", payload) raise e
最后利用上面2個方法編寫一條用例
def test01(self): try: labels = self.get_all_label() # 調用查詢標簽方法,獲取所有可用標簽 # n = isinstance(labels, Iterable) # print(n) if labels: label = random.choice(labels) # 從獲取到的標簽列表中隨機取出一個 seq = label["seq"] # 從取出的一個標簽中,獲取其seq值 data = self.add_draft(seq) # 調用生成草稿數據方法,並將seq傳入 print("使用的標簽名:{},對應的標簽seq:{},返回的草稿編碼:{}".format(label["labelName"], label["seq"], data["data"])) elif labels is None: print("標簽菜單暫無可用數據,請先去添加標簽") except Exception as e: print("錯誤詳情:", e) raise e
在實際編寫過程中,由於每個接口的實際情況不同,所以要做相應的處理,例如,
1. 在獲取標簽過程中,只有啟用狀態的標簽才能使用,所以需要判斷下標簽的狀態;
2. 需要考慮下假如標簽菜單為空怎么辦?這個時候獲取標簽的方法就拿不到數據,所以也要加個判斷,沒有標簽數據時,這個方法要返回什么內容,以及后續接口做相應處理,避免當接收不到seq時報異常;
3. 另外就是有些接口在開發時定義的不是很規范,雖然返回的一大批數據,但是有些數據可能少個字段,例如上述獲取標簽接口的某些返回內容中缺少seq,那在提取每一組的seq時,就要判斷seq這個字段是不是存在,存在則提取,不存在則略過。
其實這些問題也是在實際運行過程中發現的缺陷,很多異常情況沒有考慮到,腳本不是寫完就完了的,還要放到環境中運行,只有這樣才會發現腳本不完善的地方。
這只是一個簡單例子,實際情況可能更復雜一些,例如需要返回多個參數的情況或者把多個接口的返回值傳遞給一個接口等等;
不過道理都是一樣的,要學會分析接口返回內容的結構,提取自己想要的值。更多細節以及技巧等待大家在實際使用過程中發現
完整demo:
login.py,使用cookie跳過驗證碼登錄,可以參考:https://www.cnblogs.com/hanmk/p/9101275.html
# coding:utf-8 import requests # from requests.cookies import RequestsCookieJar class Login: @staticmethod def test_login(): s = requests.session() jar = requests.cookies.RequestsCookieJar() # 創建一個Cookie Jar對象 jar.set('XXX', 'xxx') # 向Cookie Jar對象中添加cookie值 jar.set('XXX', 'xxx') jar.set('XXX', 'xxx') s.cookies.update(jar) # 把cookies追加到Session中 return s
test.py
# coding:utf-8 import unittest from hmk.login import Login import warnings import json import random from collections import Iterable class ModuleList(unittest.TestCase): def setUp(self): warnings.simplefilter("ignore", ResourceWarning) self.s = Login() self.url = 'http://127.0.0.1:8080/XXX' self.header = { "Accept": "application/json, text/javascript, */*; q=0.01", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Origin": "http://127.0.0.1:8080", "Referer": "http://127.0.0.1:8080XXX", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", "X-Requested-With": "XMLHttpRequest" } def get_all_label(self): """獲取菜單中所有標簽數據""" url = "http://127.0.0.1:8080XXX" payload = { "page": "1", "rows": "10", "sort": "labelStatus", "order": "asc" } response = self.s.test_login().post(url, data=payload, headers=self.header, verify=False) data = json.loads(response.content) # print(data) try: self.assertIn("rows", data) self.assertIn("total", data) if data["rows"]: labels = [] # 定義一個列表存查詢到的所有標簽數據 for t in data["rows"]: """以列表中嵌套字典的格式保存,易於調用""" if t["labelStatus"] == 0: """如果labelStatus為0則追加到列表中""" labels.append( {"seq": t["seq"], "labelCode": t["labelCode"], "labelName": t["labelName"], "labelStatus": t["labelStatus"]} ) # print(labels) return labels else: labels = None return labels except Exception as e: print("請求url:", response.url) print("傳入參數:", payload) raise e def add_draft(self, seq=None): """新增草稿""" url = "http://127.0.0.1:8080/XXX" payload = { "title": "XXX", "applyType": 0, "hotFlag": 1, "content": "XXX", "replyContent": "XXX", "labelList[0].lseq": seq, # 接收傳入的seq "faqList[0].content": "XXX", "faqList[0].replyContent": "XXX", "fnType": 0 } response = self.s.test_login().post(url, data=payload, headers=self.header, verify=False) data = response.json() # print(data) try: self.assertEqual(data["success"], "true") self.assertEqual(data["successful"], True)return data except Exception as e: print("請求url:", response.url) print("傳入參數:", payload) raise e def test01(self): try: labels = self.get_all_label() # 調用查詢標簽方法,獲取所有可用標簽 # n = isinstance(labels, Iterable) # print(n) if labels: label = random.choice(labels) # 從獲取到的標簽列表中隨機取出一個 seq = label["seq"] # 從取出的一個標簽中,獲取其seq值 data = self.add_draft(seq) # 調用生成草稿數據方法,並將seq傳入 print("使用的標簽名:{},對應的標簽seq:{},返回的草稿編碼:{}".format(label["labelName"], label["seq"], data["data"])) elif labels is None: print("標簽菜單暫無可用數據,請先去添加標簽") except Exception as e: print("錯誤詳情:", e) raise e
if __name__ == '__main__': # unittest.main() suite = unittest.TestSuite() suite.addTest(ModuleList('test01')) runner = unittest.TextTestRunner() runner.run(suite)
喜歡點個贊吧,也可以關注我的公眾號喲,更多精彩等你發現~~
