1. 程式人生 > 程式設計 >Python實現http介面自動化測試的示例程式碼

Python實現http介面自動化測試的示例程式碼

網上http介面自動化測試Python實現有很多,我也是在慕課網上學習了相關課程,並實際操作了一遍,於是進行一些總結,便於以後回顧溫習,有許多不完善的地方,希望大神們多多指教!

介面測試常用的工具有fiddler,postman,jmeter等,使用這些工具測試時,需要了解常用的介面型別和區別,比如我用到的post和get請求,表面上看get用於獲取資料post用於修改資料,兩者傳遞引數的方式也有不一樣,get是直接在url裡通過?來連線引數,而post則是把資料放在HTTP的包體內(request body),兩者的本質就是TCP連結,並無差別,但是由於HTTP的規定和瀏覽器/伺服器的限制,導致他們在應用過程中體現出一些不同。具體的可以參考此博文,講解的比較通俗易懂。這些在工具中可以直接選擇,python需要藉助requests包。

確定好介面型別後,需要做的就是準備測試資料和設計測試用例了,測試用例比如說可以判斷返回狀態響應碼,或者對返回資料進行判別等,具體可以參考postman中的echo.collections,對於python可以用unittest來組織測試用例和新增斷言進行判斷。而對於測試資料的準備,需要做到資料和業務儘量分離,即將測試資料引數化,在工具中可以通過新增變數的形式實現,對於python設計到的有關包有xlrd,json,如果需要連線資料庫還需要mysql。
測試完成後生產報告或者傳送郵件,也可以使用HTMLTestRunner和smtplib等。
我也從這三大方面進行總結:

1. 介面方法實現和封裝


requests庫可以很好的幫助我們實現HTTP請求,API參考文件,這裡我建立了runmethod.py,裡面包含RunMethod類:

這裡寫圖片描述

這裡需要注意就是python預設引數和可選引數要放在必選引數後面,對於相應資料使用json格式進行返回。引數verify=false表示忽略對 SSL 證書的驗證。

2.組織測試和生成報告

使用unittest來組織測試、新增測試用例和斷言,測試報告可以下載HTMLTestRunner.py並放在python安裝路徑lib下即可,程式碼如下:

#coding:utf-8
import unittest
import json
import HTMLTestRunner
from mock import mock
#from demo import RunMain
from runmethod import RunMethod
from mock_demo import mock_test
import os
class TestMethod(unittest.TestCase):
	def setUp(self):
		#self.run=RunMain()
		self.run = RunMethod()
	def test_01(self):
		url = 'http://coding.imooc.com/api/cate'
		data = {
			'timestamp':'1507034803124','uid':'5249191','uuid':'5ae7d1a22c82fb89c78f603420870ad7','secrect':'078474b41dd37ddd5efeb04aa591ec12','token':'7d6f14f21ec96d755de41e6c076758dd','cid':'0','errorCode':1001
		}
		#self.run.run_main = mock.Mock(return_value=data)
		res = mock_test(self.run.run_main,data,url,"POST",data)
		#res = self.run.run_main(url,'POST',data)
		print(res)
		self.assertEqual(res['errorCode'],1001,"測試失敗")


	@unittest.skip('test_02')	
	def test_02(self):
		
		url = 'http://coding.imooc.com/api/cate'
		data = {
			'timestamp':'1507034803124','cid':'0'

		}

		res = self.run.run_main(url,'GET',data)
		self.assertEqual(res['errorCode'],1006,"測試失敗")

	def test_03(self):
		url = 'http://coding.imooc.com/api/cate'
		data = {
			'timestamp':'1507034803124','status':11
			}

		res = mock_test(self.run.run_main,data)
		print(res)
		self.assertGreater(res['status'],10,'測試通過')

if __name__ == '__main__':

	filepath = os.getcwd()+'\\report.html'
	fp = open(filepath,'wb+')
	suite = unittest.TestSuite()
	suite.addTest(TestMethod('test_01'))
	suite.addTest(TestMethod('test_02'))
	suite.addTest(TestMethod('test_03'))
	runner = HTMLTestRunner.HTMLTestRunner(stream=fp,title='this is demo test')
	runner.run(suite)
	#unittest.main()

這裡setUp()方法用來在測試之前執行,同樣的有tearDown()方法,測試case以test開頭進行編寫,然後使用TestSuit類生成測試套件,將case新增進去,執行run suite即可。當測試用例較多時,可以生成多個測試類別,然後使用TestLoader().LoadTestsFromTestCase(測試類)生成測試用例,再加入testsuite執行。
在這裡,我使用了學習到的mock方法,mock即模擬資料,當我們無法實際執行獲得資料時可以使用mock方法,模擬生成我們需要判別的資料,這裡mock_test方法同樣進行了封裝:

#coding:utf-8
from mock import mock
def mock_test(mock_method,request_data,method,response_data):
	mock_method = mock.Mock(return_value=response_data)
	res = mock_method(url,request_data)
	return res

這裡模擬的是self.run.run_main()方法,將這個方法的返回值設為response_data,而最終我們要判斷的是返回值res,可以結合test_02對比,

res = self.run.run_main(url,data)

所以又需要傳入引數url,最後返回相應資料即可,

res = mock_test(self.run.run_main,data)

這裡我假設返回的資料為data,隨意添加了幾個判斷條件errorCode==1001status>10作為判斷依據。最後生成報告如下:

這裡寫圖片描述

3 測試資料處理

這一部分主要包括設計測試資料,資料提取和引數化,以及解決資料依賴。這裡還是以慕課網上學習的例子為例,主要依據測試目的和使用流程來設計,如下圖:

這裡寫圖片描述

這裡首先涉及到的就是對Excel表格的操作,匯入相關庫import xlrd,先對如上表的測試用例進行配置檔案編寫:

class global_var:
	Id = '0'
	request_name = '1'
	url = '2'
	run = '3'
	request_way = '4'
	header = '5'
	case_depend = '6'
	data_depend = '7'
	field_depend = '8'
	data = '9'
	expect = '10'
	result = '11'

再定義返回該列的函式,例如獲取caseId和URL:

def get_id():
	return global_var.Id
def get_url():
	return global_var.url

3.1操作Excel檔案

然後我們再編寫操作Excel的模組,主要包含了對Excel表格的操作,獲取表單、行、列、單元格內容等。

import xlrd
from xlutils.copy import copy
class OperationExcel:
	def __init__(self,file_name=None,sheet_id=None):
		if file_name:
			self.file_name = file_name
			self.sheet_id = sheet_id	
		else:
			self.file_name = '/dataconfig/case1.xls'
			self.sheet_id = 0
		self.data = self.get_data()
	#獲取sheets的內容
	def get_data(self):
		data = xlrd.open_workbook(self.file_name)
		tables = data.sheets()[self.sheet_id]
		return tables
	#獲取單元格的行數
	def get_lines(self):
		tables = self.data
		return tables.nrows
	#獲取某一個單元格的內容
	def get_cell_value(self,row,col):
		return self.data.cell_value(row,col)
	#寫入資料
	def write_value(self,col,value):
		'''寫入excel資料row,value'''
		read_data = xlrd.open_workbook(self.file_name)
		write_data = copy(read_data)
		sheet_data = write_data.get_sheet(0)
		sheet_data.write(row,value)
		write_data.save(self.file_name)

其中寫資料用於將執行結果寫入Excel檔案,先用copy複製整個檔案,通過get_sheet()獲取的sheet有write()方法。

3.2操作json檔案

對於請求資料,我是根據關鍵字從json檔案裡取出欄位,所以還需要json格式的資料檔案,如下。對應請求資料中的各個關鍵字:

這裡寫圖片描述

所以還需要編寫對應操作json檔案的模組:

import json
class OperetionJson:
	def __init__(self,file_path=None):
		if file_path == None:
			self.file_path = '/dataconfig/user.json'
		else:
			self.file_path = file_path
		self.data = self.read_data()
	#讀取json檔案
	def read_data(self):
		with open(self.file_path) as fp:
			data = json.load(fp)
			return data
	#根據關鍵字獲取資料
	def get_data(self,id):
		print(type(self.data))
		return self.data[id]

讀寫操作使用的是json.load(),json.dump() 傳入的是檔案控制代碼。

3.3 獲得測試資料

在定義好Excel和json操作模組後,我們將其應用於我們的測試表單,定義一個獲取資料模組:

from util.operation_excel import OperationExcel
import data.data_config
from util.operation_json import OperetionJson
class GetData:
	def __init__(self):
		self.opera_excel = OperationExcel()
	#去獲取excel行數,就是我們的case個數	
	def get_case_lines(self):
		return self.opera_excel.get_lines()
	#獲取是否執行
	def get_is_run(self,row):
		flag = None
		col = int(data_config.get_run())
		run_model = self.opera_excel.get_cell_value(row,col)
		if run_model == 'yes':
			flag = True
		else:
			flag = False
		return flag
	#是否攜帶header
	def is_header(self,row):
		col = int(data_config.get_header())
		header = self.opera_excel.get_cell_value(row,col)
		if header != '':
			return header
		else:
			return None
	#獲取請求方式
	def get_request_method(self,row):
		col = int(data_config.get_run_way())
		request_method = self.opera_excel.get_cell_value(row,col)
		return request_method
	#獲取url
	def get_request_url(self,row):
		col = int(data_config.get_url())
		url = self.opera_excel.get_cell_value(row,col)
		return url
	#獲取請求資料
	def get_request_data(self,row):
		col = int(data_config.get_data())
		data = self.opera_excel.get_cell_value(row,col)
		if data == '':
			return None
		return data
	#通過獲取關鍵字拿到data資料
	def get_data_for_json(self,row):
		opera_json = OperetionJson()
		request_data = opera_json.get_data(self.get_request_data(row))
		return request_data
	#獲取預期結果
	def get_expcet_data(self,row):
		col = int(data_config.get_expect())
		expect = self.opera_excel.get_cell_value(row,col)
		if expect == '':
			return None
		return expect
	def write_result(self,value):
		col = int(data_config.get_result())
		self.opera_excel.write_value(row,value)

該模組將Excel操作類例項化後用於操作測試表單,分別獲得測試執行所需的各種條件。

3.4 判斷條件

這裡判斷一個case是否通過,是將實際結果和預期結果進行對比,比如,狀態碼status是不是200,或者在返回資料中檢視是否含有某一欄位:

import json
import operator as op
class CommonUtil:
	def is_contain(self,str_one,str_two):
		'''
		判斷一個字串是否再另外一個字串中
		str_one:查詢的字串
		str_two:被查詢的字串
		'''
		flag = None
		#先將返回的res進行格式轉換,unicode轉成string型別
		if isinstance(str_one,unicode):
			str_one = str_one.encode('unicode-escape').decode('string_escape')
		return op.eq(str_one,str_two)
		if str_one in str_two:
			flag = True
		else:
			flag = False
		return flag

	def is_equal_dict(self,dict_one,dict_two):
		'''判斷兩個字典是否相等'''
		if isinstance(dict_one,str):
			dict_one = json.loads(dict_one)
		if isinstance(dict_two,str):
			dict_two = json.loads(dict_two)
		return op.eq(dict_one,dict_two)

所以我們獲得expec資料和相應資料,再呼叫這個類別的is_contain() 方法就能判斷。

3.5 資料依賴問題

當我們要執行的某個case的相應資料依賴於前面某個case的返回資料時,我們需要對相應資料進行更新,比如case12的相應資料request_data[資料依賴欄位]的值應該更新於case11的返回資料response_data[依賴的返回欄位] 。那麼我們就需要先執行case11拿到返回資料,再寫入case12的相應資料,首先對操作Excel的模組進行更新加入:

#獲取某一列的內容
	def get_cols_data(self,col_id=None):
		if col_id != None:
			cols = self.data.col_values(col_id)
		else:
			cols = self.data.col_values(0)
		return cols
	#根據對應的caseid找到對應的行號
	def get_row_num(self,case_id):
		num = 0
		cols_data = self.get_cols_data()
		for col_data in cols_data:
			if case_id in col_data:
				return num
			num = num+1
	#根據行號,找到該行的內容
	def get_row_values(self,row):
		tables = self.data
		row_data = tables.row_values(row)
		return row_data
	#根據對應的caseid 找到對應行的內容
	def get_rows_data(self,case_id):
		row_num = self.get_row_num(case_id)
		rows_data = self.get_row_values(row_num)
		return rows_data

即我們通過依賴的caseId找到對應的行號,拿到整行的內容。我們預設拿到列0的內容(即caseId)迴圈整列找到依賴的caseId在第幾行,然後返回整行資料,即實現方法get_rows_data(case_id) 。然後再去執行和更新,我們編寫一個專門處理依賴資料的模組,同時,為了獲取依賴資料,還需要對獲取資料模組進行更新如下:

#獲取依賴資料的key
	def get_depend_key(self,row):
		col = int(data_config.get_data_depend())
		depent_key = self.opera_excel.get_cell_value(row,col)
		if depent_key == "":
			return None
		else:
			return depent_key
	#判斷是否有case依賴
	def is_depend(self,row):
		col = int(data_config.get_case_depend())
		depend_case_id = self.opera_excel.get_cell_value(row,col)
		if depend_case_id == "":
			return None
		else:
			return depend_case_id
	#獲取資料依賴欄位
	def get_depend_field(self,row):
		col = int(data_config.get_field_depend())
		data = self.opera_excel.get_cell_value(row,col)
		if data == "":
			return None
		else:
			return data

將方法應用於專門處理依賴資料的模組:

from util.operation_excel import OperationExcel
from base.runmethod import RunMethod
from data.get_data import GetData
from jsonpath_rw import jsonpath,parse
class DependdentData:
	def __init__(self,case_id):
		self.case_id = case_id
		self.opera_excel = OperationExcel()
		self.data = GetData()
	#通過case_id去獲取該case_id的整行資料
	def get_case_line_data(self):
		rows_data = self.opera_excel.get_rows_data(self.case_id)
		return rows_data
	#執行依賴測試,獲取結果
	def run_dependent(self):
		run_method = RunMethod()
		row_num = self.opera_excel.get_row_num(self.case_id)
		request_data = self.data.get_data_for_json(row_num)
		#header = self.data.is_header(row_num)
		method = self.data.get_request_method(row_num)
		url = self.data.get_request_url(row_num)
		res = run_method.run_main(method,request_data)
		return json.loads(res)#返回資料是字串需要轉成json格式方便後續查詢
	#根據依賴的key去獲取執行依賴測試case的響應,然後返回
	def get_data_for_key(self,row):
		depend_data = self.data.get_depend_key(row)
		response_data = self.run_dependent()
		json_exe = parse(depend_data)
		madle = json_exe.find(response_data)
		return [math.value for math in madle][0]

其中jsonpath用於找到多層級資料,類似於xpath,即通過依賴欄位表示的層級關係在返回資料中找到對應的值,最後再執行該case時把資料更新。

3.6 主流程

把上述所有模組匯入,編寫主流程模組:

from util.operation_excel import OperationExcel
from base.runmethod import RunMethod
from data.get_data import GetData
from jsonpath_rw import jsonpath,row):
		depend_data = self.data.get_depend_key(row)
		response_data = self.run_dependent()
		json_exe = parse(depend_data)
		madle = json_exe.find(response_data)
		return [math.value for math in madle][0]

這樣我們就完成了測試執行,並對結果進行了統計,同時解決了資料依賴問題。

到此這篇關於Python實現http介面自動化測試的示例程式碼的文章就介紹到這了,更多相關Python http介面自動化測試內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!