摘抄:今天給大家分享一個簡單的python腳本,使用python進行http的接口測試,腳本很簡單,邏輯是:讀取excel寫好的測試用例,然后根據excel中的用例內容進行調用,判斷預期結果中的返回值是否和返回報文中的值一致,如果不一致則根據用例標題把bug提交到bug管理系統,這里使用的bug管理系統是bugfree。
實現步驟:
1、讀取excel,保存測試用例中的內容;
2、根據excel中的請求url和參數拼接請求報文,調用接口,並保存返回報文;
3、讀取返回報文,和預期結果對比,不一致的往bugfree數據庫中寫入一條bug,並且把請求報文、返回報文和測試結果寫到測試用例的excel中。
http接口最常用的兩種請求方式,POST和GET兩種方法,請求都是類似下面例子的url。
例子:http://127.0.0.1:8080/rest/login?oper_no=marry&id=10
需要用的到幾個模塊,requests、xlrd(讀取excel)、xlutils(寫excel)、MySQLdb(連接數據庫)這四個模塊都是第三方模塊,需要自己單獨安裝,用到的一些python中的方法和內置函數也都做了說明,本文使用的python版本是python2.7。
首先先寫好excel的用例模板,需要有的字段 項目、用例id、接口名稱、用例描述、請求方式、url請求地址、請求參數(多個的參數話用;分號隔開)、結果驗證(多個的參數話用;分號隔開)、請求報文、返回報文、測試人員、測試結果
整體代碼如下,注釋加的很詳細了,有不明白的可以給我留言
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
|
# -*- coding:utf-8 -*-
import requests, xlrd, MySQLdb, time, sys
#導入需要用到的模塊
from xlutils import copy
#從xlutils模塊中導入copy這個函數
def readExcel(file_path):
'''
讀取excel測試用例的函數
:param file_path:傳入一個excel文件,或者文件的絕對路徑
:return:返回這個excel第一個sheet頁中的所有測試用例的list
'''
try:
book = xlrd.open_workbook(file_path)#打開excel
except Exception,e:
#如果路徑不在或者excel不正確,返回報錯信息
print '路徑不在或者excel不正確',e
return e
else:
sheet = book.sheet_by_index(0)#取第一個sheet頁
rows= sheet.nrows#取這個sheet頁的所有行數
case_list = []#保存每一條case
for i in range(rows):
if i !=0:
#把每一條測試用例添加到case_list中
case_list.append(sheet.row_values(i))
#調用接口測試的函數,把存所有case的list和excel的路徑傳進去,因為后面還需要把返回報文和測試結果寫到excel中,
#所以需要傳入excel測試用例的路徑,interfaceTest函數在下面有定義
interfaceTest(case_list,file_path)
def interfaceTest(case_list,file_path):
res_flags = []
#存測試結果的list
request_urls = []
#存請求報文的list
responses = []
#存返回報文的list
for case in case_list:
'''
先遍歷excel中每一條case的值,然后根據對應的索引取到case中每個字段的值
'''
try:
'''
這里捕捉一下異常,如果excel格式不正確的話,就返回異常
'''
#項目,提bug的時候可以根據項目來提
product = case[0]
#用例id,提bug的時候用
case_id = case[1]
#接口名稱,也是提bug的時候用
interface_name = case[2]
#用例描述
case_detail = case[3]
#請求方式
method = case[4]
#請求url
url = case[5]
#入參
param = case[6]
#預期結果
res_check = case[7]
#測試人員
tester = case[10]
except Exception,e:
return '測試用例格式不正確!%s'%e
if param== '':
'''
如果請求參數是空的話,請求報文就是url,然后把請求報文存到請求報文list中
'''
new_url = url#請求報文
request_urls.append(new_url)
else:
'''
如果請求參數不為空的話,請求報文就是url+?+參數,格式和下面一樣
http://127.0.0.1:8080/rest/login?oper_no=marry&id=100,然后把請求報文存到請求報文list中
'''
new_url = url+'?'+urlParam(param)#請求報文
'''
excel里面的如果有多個入參的話,參數是用;隔開,a=1;b=2這樣的,請求的時候多個參數要用&連接,
要把;替換成&,所以調用了urlParam這個函數,把參數中的;替換成&,函數在下面定義的
'''
request_urls.append(new_url)
if method.upper() == 'GET':
'''
如果是get請求就調用requests模塊的get方法,.text是獲取返回報文,保存返回報文,
把返回報文存到返回報文的list中
'''
print new_url
results = requests.get(new_url).text
print results
responses.append(results)
'''
獲取到返回報文之后需要根據預期結果去判斷測試是否通過,調用查看結果方法
把返回報文和預期結果傳進去,判斷是否通過,readRes方法在下面定義了。
'''
res = readRes(results,res_check)
else:
'''
如果不是get請求,也就是post請求,就調用requests模塊的post方法,.text是獲取返回報文,
保存返回報文,把返回報文存到返回報文的list中
'''
results = requests.post(new_url).text
responses.append(results)
'''
獲取到返回報文之后需要根據預期結果去判斷測試是否通過,調用查看結果方法
把返回報文和預期結果傳進去,判斷是否通過,readRes方法會返回測試結果,如果返回pass就
說明測試通過了,readRes方法在下面定義了。
'''
res = readRes(results,res_check)
if 'pass' in res:
'''
判斷測試結果,然后把通過或者失敗插入到測試結果的list中
'''
res_flags.append('pass')
else:
res_flags.append('fail')
'''
如果不通過的話,就調用寫bug的方法,把case_id、接口名稱、請求報文、返回報文和預期結果傳進去
writeBug方法在下面定義了,具體實現是先連接數據庫,然后拼sql,插入到bug表中
'''
writeBug(case_id,interface_name,new_url,results,res_check)
'''
全部用例執行完之后,會調用copy_excel方法,把測試結果寫到excel中,
每一條用例的請求報文、返回報文、測試結果,這三個每個我在上面都定義了一個list
來存每一條用例執行的結果,把源excel用例的路徑和三個list傳進去調用即可,copy_excel方
法在下面定義了,也加了注釋
'''
copy_excel(file_path,res_flags,request_urls,responses)
def readRes(res,res_check):
'''
:param res: 返回報文
:param res_check: 預期結果
:return: 通過或者不通過,不通過的話會把哪個參數和預期不一致返回
'''
'''
返回報文的例子是這樣的{"id":"J_775682","p":275.00,"m":"458.00"}
excel預期結果中的格式是xx=11;xx=22這樣的,所以要把返回報文改成xx=22這樣的格式
所以用到字符串替換,把返回報文中的":"和":替換成=,返回報文就變成
{"id=J_775682","p=275.00,"m=458.00"},這樣就和預期結果一樣了,當然也可以用python自帶的
json模塊來解析json串,但是有的返回的不是標准的json格式,處理起來比較麻煩,這里我就用字符串的方法了
'''
res = res.replace('":"',"=").replace('":',"=")
'''
res_check是excel中的預期結果,是xx=11;xx=22這樣的
所以用split分割字符串,split是python內置函數,切割字符串,變成一個list
['xx=1','xx=2']這樣的,然后遍歷這個list,判斷list中的每個元素是否存在這個list中,
如果每個元素都在返回報文中的話,就說明和預期結果一致
上面我們已經把返回報文變成{"id=J_775682","p=275.00,"m=458.00"}
'''
res_check = res_check.split(';')
for s in res_check:
'''
遍歷預期結果的list,如果在返回報文中,什么都不做,pass代表什么也不做,全部都存在的話,就返回pass
如果不在的話,就返回錯誤信息和不一致的字段,因為res_check是從excel里面讀出來的
字符Unicode類型的的,python的字符串是str類型的,所以要用str方法強制類型轉換,轉換成string類型的
'''
if s in res:
pass
else:
return '錯誤,返回參數和預期結果不一致'+str(s)
return 'pass'
def urlParam(param):
'''
參數轉換,把參數轉換為'xx=11&xx=2這樣'
'''
return param.replace(';','&')
def copy_excel(file_path,res_flags,request_urls,responses):
'''
:param file_path: 測試用例的路徑
:param res_flags: 測試結果的list
:param request_urls: 請求報文的list
:param responses: 返回報文的list
:return:
'''
'''
這個函數的作用是寫excel,把請求報文、返回報文和測試結果寫到測試用例的excel中
因為xlrd模塊只能讀excel,不能寫,所以用xlutils這個模塊,但是python中沒有一個模塊能
直接操作已經寫好的excel,所以只能用xlutils模塊中的copy方法,copy一個新的excel,才能操作
'''
#打開原來的excel,獲取到這個book對象
book = xlrd.open_workbook(file_path)
#復制一個new_book
new_book = copy.copy(book)
#然后獲取到這個復制的excel的第一個sheet頁
sheet = new_book.get_sheet(0)
i = 1
for request_url,response,flag in zip(request_urls,responses,res_flags):
'''
同時遍歷請求報文、返回報文和測試結果這3個大的list
然后把每一條case執行結果寫到excel中,zip函數可以將多個list放在一起遍歷
因為第一行是表頭,所以從第二行開始寫,也就是索引位1的位置,i代表行
所以i賦值為1,然后每寫一條,然后i+1, i+=1同等於i=i+1
請求報文、返回報文、測試結果分別在excel的8、9、11列,列是固定的,所以就給寫死了
后面跟上要寫的值,因為excel用的是Unicode字符編碼,所以前面帶個u表示用Unicode編碼
否則會有亂碼
'''
sheet.write(i,8,u'%s'%request_url)
sheet.write(i,9,u'%s'%response)
sheet.write(i,11,u'%s'%flag)
i+=1
#寫完之后在當前目錄下(可以自己指定一個目錄)保存一個以當前時間命名的測試結果,time.strftime()是格式化日期
new_book.save('%s_測試結果.xls'%time.strftime('%Y%m%d%H%M%S'))
def writeBug(bug_id,interface_name,request,response,res_check):
'''
這個函數用來連接數據庫,往bugfree數據中插入bug,拼sql,執行sql即可
:param bug_id: bug序號
:param interface_name: 接口名稱
:param request: 請求報文
:param response: 返回報文
:param res_check: 預期結果
:return:
'''
bug_id = bug_id.encode('utf-8')
interface_name = interface_name.encode('utf-8')
res_check = res_check.encode('utf-8')
response = response.encode('utf-8')
request = request.encode('utf-8')
'''
因為上面幾個字符串是從excel里面讀出來的都是Unicode字符集編碼的,
python的字符串上面指定了utf-8編碼的,所以要把它的字符集改成utf-8,才能把sql拼起來
encode方法可以指定字符集
'''
#取當前時間,作為提bug的時間
now = time.strftime("%Y-%m-%d %H:%M:%S")
#bug標題用bug編號加上接口名稱然后加上_結果和預期不符,可以自己隨便定義要什么樣的bug標題
bug_title = bug_id + '_' + interface_name + '_結果和預期不符'
#復現步驟就是請求報文+預期結果+返回報文
step = '[請求報文]<br />'+request+'<br/>'+'[預期結果]<br/>'+res_check+'<br/>'+'<br/>'+'[響應報文]<br />'+'<br/>'+response
#拼sql,這里面的項目id,創建人,嚴重程度,指派給誰,都在sql里面寫死,使用的時候可以根據項目和接口
# 來判斷提bug的嚴重程度和提交給誰
sql = "INSERT INTO `bf_bug_info` (`created_at`, `created_by`, `updated_at`, `updated_by`, `bug_status`, `assign_to`, `title`, `mail_to`, `repeat_step`, `lock_version`, `resolved_at`, `resolved_by`, `closed_at`, `closed_by`, `related_bug`, `related_case`, `related_result`, " \
"`productmodule_id`, `modified_by`, `solution`, `duplicate_id`, `product_id`, " \
"`reopen_count`, `priority`, `severity`) VALUES ('%s', '1', '%s', '1', 'Active', '1', '%s', '系統管理員', '%s', '1', NULL , NULL, NULL, NULL, '', '', '', NULL, " \
"'1', NULL, NULL, '1', '0', '1', '1');"%(now,now,bug_title,step)
#建立連接,使用MMySQLdb模塊的connect方法連接mysql,傳入賬號、密碼、數據庫、端口、ip和字符集
coon = MySQLdb.connect(user='root',passwd='123456',db='bugfree',port=3306,host='127.0.0.1',charset='utf8')
#建立游標
cursor = coon.cursor()
#執行sql
cursor.execute(sql)
#提交
coon.commit()
#關閉游標
cursor.close()
#關閉連接
coon.close()
if __name__ == '__main__':
'''
然后進行調用,調用的時候需要傳入一個excel,調用方式是 python test.py test_case.xls
sys.argv[1]的意思是取傳入的第二個參數,也就是索引是1的,
第一個是這個python文件的文件名,如果不傳入參數運行的話,會提示錯誤,如果正確的話,
會調用讀excel的程序,執行用例,運行完成后,會打印Done
'''
try:
filename = sys.argv[1]
except IndexError,e:
print 'Please enter a correct testcase! \n e.x: python gkk.py test_case.xls'
else:
readExcel(filename)
print 'Done!
|