項目背景
公司內部的軟件采用B/S架構,管理實驗室數據,實現數據的存儲和分析統計。大部分是數據的增刪改查,由於還在開發階段,所以UI界面的變化非常快,之前嘗試過用python+selenium進行UI自動化測試,后來發現今天剛寫好的腳本第二天前端就改了頁面,又得重新去定位元素什么的,消耗大量的精力與時間維護自動化腳本。針對此種情況,對接口測試較為有效。
工具
由於開發那里不能提供后台代碼給我,只能通過抓包分析。使用fiddler抓包,發現前端與后台都是采用POST方法交互,前端POST數據,后台返回數據。這樣也比較簡單粗暴,直接針對每個接口POST測試數據,然后觀察返回值就好了。
使用excel編寫測試用例和數據,requests發送HTTP請求。
功能模塊
通過xlrd庫讀取excel中的測試用例和數據
requests負責發送數據並接收后台返回的數據
針對測試結果,需要保存測試日志並生成測試報告,采用python自帶的logging記錄日志,測試報告采用html格式。
同時測試完成后,需要將測試報告發送給相關的開發人員,需要有自動發送郵件的功能
目錄結構
代碼實現
#通過自帶的ConfigParser模塊,讀取郵件發送的配置文件,作為字典返回 import ConfigParser def get_conf(): conf_file = ConfigParser.ConfigParser() conf_file.read(os.path.join(os.getcwd(),'conf.ini')) conf = {} conf['sender'] = conf_file.get("email","sender") conf['receiver'] = conf_file.get("email","receiver") conf['smtpserver'] = conf_file.get("email","smtpserver") conf['username'] = conf_file.get("email","username") conf['password'] = conf_file.get("email","password") return conf
配置文件格式
這個logging不熟悉的可以google一下,還是挺有用的,需要自己配置一下。需要手動新建一個空白的.log文件。
#此處使用python自帶的logging模塊,用來作為測試日志,記錄測試中系統產生的信息。 import logging,os log_file = os.path.join(os.getcwd(),'log/sas.log') log_format = '[%(asctime)s] [%(levelname)s] %(message)s' #配置log格式 logging.basicConfig(format=log_format, filename=log_file, filemode='w', level=logging.DEBUG) console = logging.StreamHandler() console.setLevel(logging.DEBUG) formatter = logging.Formatter(log_format) console.setFormatter(formatter) logging.getLogger('').addHandler(console)
excel文件如下圖
python讀取excel跟讀取一個二維數組差不多,下標也是從0開始
#讀取testcase excel文件,獲取測試數據,調用interfaceTest方法,將結果保存至errorCase列表中。 import xlrd,hashlib,json def runTest(testCaseFile): testCaseFile = os.path.join(os.getcwd(),testCaseFile) if not os.path.exists(testCaseFile): logging.error('測試用例文件不存在!') sys.exit() testCase = xlrd.open_workbook(testCaseFile) table = testCase.sheet_by_index(0) errorCase = [] #用於保存接口返回的內容和HTTP狀態碼 s = None for i in range(1,table.nrows): if table.cell(i, 9).vale.replace('\n','').replace('\r','') != 'Yes': continue num = str(int(table.cell(i, 0).value)).replace('\n','').replace('\r','') api_purpose = table.cell(i, 1).value.replace('\n','').replace('\r','') api_host = table.cell(i, 2).value.replace('\n','').replace('\r','') request_method = table.cell(i, 4).value.replace('\n','').replace('\r','') request_data_type = table.cell(i, 5).value.replace('\n','').replace('\r','') request_data = table.cell(i, 6).value.replace('\n','').replace('\r','') encryption = table.cell(i, 7).value.replace('\n','').replace('\r','') check_point = table.cell(i, 8).value if encryption == 'MD5': #如果數據采用md5加密,便先將數據加密 request_data = json.loads(request_data) request_data['pwd'] = md5Encode(request_data['pwd']) status, resp, s = interfaceTest(num, api_purpose, api_host, request_url, request_data, check_point, request_methon, request_data_type, s) if status != 200 or check_point not in resp: #如果狀態碼不為200或者返回值中沒有檢查點的內容,那么證明接口產生錯誤,保存錯誤信息。 errorCase.append((num + ' ' + api_purpose, str(status), 'http://'+api_host+request_url, resp)) return errorCase
下面的就是接口部分
由於所有的操作必須在系統登錄之后進行,一開始沒有注意到cookie這一點,每讀取一個測試用例,都會新建一個session,導致無法維護上一次請求的cookie。然后將cookie添加入請求頭中,但是第二個用例仍然無法執行成功。后來用fiddler抓包分析了一下,發現cookie的值竟然是每一次操作后都會變化的!!!
所以只能通過session自動維護cookie。
在interfaceTest函數中,返回三個值,分別是HTTP CODE,HTTP返回值與session。再將上一次請求的session作為入參傳入interfaceTest函數中,在函數內部判斷session是否存在,如果不為None,那么直接利用傳入的session執行下一個用例,如果為None,那么新建一個session。
#接受runTest的傳參,利用requests構造HTTP請求 import requests def interfaceTest(num, api_purpose, api_host, request_method, request_data_type, request_data, check_point, s=None) headers = {'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With' : 'XMLHttpRequest', 'Connection' : 'keep-alive', 'Referer' : 'http://' + api_host, 'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36' } if s == None: s = requests.session() if request_method == 'POST': if request_url != '/login' : r = s.post(url='http://'+api_host+request_url, data = json.loads(request_data), headers = headers) #由於此處數據沒有經過加密,所以需要把Json格式字符串解碼轉換成**Python對象** elif request_url == '/login' : s = requests.session() r = s.post(url='http://'+api_host+request_url, data = request_data, headers = headers) #由於登錄密碼不能明文傳輸,采用MD5加密,在之前的代碼中已經進行過json.loads()轉換,所以此處不需要解碼 else: logging.error(num + ' ' + api_purpose + ' HTTP請求方法錯誤,請確認[Request Method]字段是否正確!!!') s = None return 400, resp, s status = r.status_code resp = r.text print resp if status == 200 : if re.search(check_point, str(r.text)): logging.info(num + ' ' + api_purpose + ' 成功,' + str(status) + ', ' + str(r.text)) return status, resp, s else: logging.error(num + ' ' + api_purpose + ' 失敗!!!,[' + str(status) + '], ' + str(r.text)) return 200, resp , None else: logging.error(num + ' ' + api_purpose + ' 失敗!!!,[' + str(status) + '],' + str(r.text)) return status, resp.decode('utf-8'), None
import hashlib def md5Encode(data): hashobj = hashlib.md5() hashobj.update(data.encode('utf-8')) return hashobj.hexdigest() def sendMail(text): mail_info = get_conf() sender = mail_info['sender'] receiver = mail_info['receiver'] subject = '[AutomationTest]接口自動化測試報告通知' smtpserver = mail_info['smtpserver'] username = mail_info['username'] password = mail_info['password'] msg = MIMEText(text,'html','utf-8') msg['Subject'] = subject msg['From'] = sender msg['To'] = ''.join(receiver) smtp = smtplib.SMTP() smtp.connect(smtpserver) smtp.login(username, password) smtp.sendmail(sender, receiver, msg.as_string()) smtp.quit() def main(): errorTest = runTest('TestCase/TestCase.xlsx') if len(errorTest) > 0: html = '<html><body>接口自動化掃描,共有 ' + str(len(errorTest)) + ' 個異常接口,列表如下:' + '</p><table><tr><th style="width:100px;text-align:left">接口</th><th style="width:50px;text-align:left">狀態</th><th style="width:200px;text-align:left">接口地址</th><th style="text-align:left">接口返回值</th></tr>' for test in errorTest: html = html + '<tr><td style="text-align:left">' + test[0] + '</td><td style="text-align:left">' + test[1] + '</td><td style="text-align:left">' + test[2] + '</td><td style="text-align:left">' + test[3] + '</td></tr>' sendMail(html) if __name__ == '__main__': main()
以上就是一個簡單的接口測試實現,參考了論壇里的大神們很多東西,還有很多不足之處。例如html格式的郵件很簡陋,可以考慮生成一個HTML的測試報告,作為附件發送。
接口方法只實現了一個POST。
轉自:https://testerhome.com/topics/4948