摘抄:今天給你們分享一個簡單的python腳本,使用python進行http的接口測試,腳本很簡單,邏輯是:讀取excel寫好的測試用例,而後根據excel中的用例內容進行調用,判斷預期結果中的返回值是否和返回報文中的值一致,若是不一致則根據用例標題把bug提交到bug管理系統,這裏使用的bug管理系統是bugfree。python
實現步驟:mysql
一、讀取excel,保存測試用例中的內容;sql
二、根據excel中的請求url和參數拼接請求報文,調用接口,並保存返回報文;數據庫
三、讀取返回報文,和預期結果對比,不一致的往bugfree數據庫中寫入一條bug,而且把請求報文、返回報文和測試結果寫到測試用例的excel中。json
http接口最經常使用的兩種請求方式,POST和GET兩種方法,請求都是相似下面例子的url。sublime-text
例子:http://127.0.0.1:8080/rest/login?oper_no=marry&id=10app
須要用的到幾個模塊,requests、xlrd(讀取excel)、xlutils(寫excel)、MySQLdb(鏈接數據庫)這四個模塊都是第三方模塊,須要本身單獨安裝,用到的一些python中的方法和內置函數也都作了說明,本文使用的python版本是python2.7。python2.7
首先先寫好excel的用例模板,須要有的字段 項目、用例id、接口名稱、用例描述、請求方式、url請求地址、請求參數(多個的參數話用;分號隔開)、結果驗證(多個的參數話用;分號隔開)、請求報文、返回報文、測試人員、測試結果函數
總體代碼以下,註釋加的很詳細了,有不明白的能夠給我留言post
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的八、九、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!
|