閑話休扯,上需求:自動讀取、執行excel里面的接口測試用例,測試完成后,返回錯誤結果並發送郵件通知。
分析:
1、設計excel表格
2、讀取excel表格
3、拼接url,發送請求
4、匯總錯誤結果、發送郵件
開始實現:
1、設計excel接口用例表格,大概長這樣:
依次為:用例編號、接口名稱、接口主host、接口路由、請求方式、請求參數類型、請求參數、斷言
這次案例中用到的接口,其實就是如何優雅的進行接口測試使用的快遞查詢接口,一時半會兒沒找到好用的,之前寫的也找不到了,只好作罷。
2、讀取excel表格,獲取每個用例的數據
import xlrd
import sys
def test_cases_in_excel(test_case_file): test_case_file = os.path.join(os.getcwd(), test_case_file) # 獲取測試用例全路徑 如:E:\Python\httprunner\interface_excel\testcases.xlsx print(test_case_file) if not os.path.exists(test_case_file): print("測試用例excel文件存在或路徑有誤!") # 找不到指定測試文件,就退出程序 os.system("exit")是用來退出cmd的 sys.exit() # 讀取excel文件 test_case = xlrd.open_workbook(test_case_file) # 獲取第一個sheet,下標從0開始 table = test_case.sheet_by_index(0) # 記錄錯誤用例 error_cases = [] # 一張表格讀取下來,其實就像個二維數組,無非是讀取第一行的第幾列的值,由於下標是從0開始,第一行是標題,所以從第二行開始讀取數據 for i in range(1, table.nrows): num = str(int(table.cell(i, 0).value)).replace("\n", "").replace("\r", "") api_name = table.cell(i, 1).value.replace("\n", "").replace("\r", "") api_host = table.cell(i, 2).value.replace("\n", "").replace("\r", "") request_url = table.cell(i, 3).value.replace("\n", "").replace("\r", "") 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", "") check_point = table.cell(i, 7).value.replace("\n", "").replace("\r", "") print(num, api_name, api_host, request_url, method, request_data_type, request_data, check_point) try: # 調用接口請求方法,后面會講到 status, resp = interface_test(num, api_name, api_host, request_url, method, request_data_type, request_data, check_point) if status != 200 or check_point not in resp: # append只接收一個參數,所以要講四個參數括在一起,當一個參數來傳遞 # 請求失敗,則向error_cases中增加一條記錄 error_cases.append((num + " " + api_name, str(status), api_host + request_url)) except Exception as e: print(e) print("第{}個接口請求失敗,請檢查接口是否異常。".format(num)) # 訪問異常,也向error_cases中增加一條記錄 error_cases.append((num + " " + api_name, "請求失敗", api_host + request_url)) return error_cases
3、拼接url,判斷請求方式(get/post),發送請求
傳入讀取用例的各種參數,先判斷請求方式,再拼接參數通過requests庫來發送請求
import requests
def interface_test(num, api_name, api_host, request_url, method, request_data_type, request_data, check_point): # 構造請求headers 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' } # 判斷請求方式,如果是GET,則調用get請求,POST調post請求,都不是,則拋出異常 if method == "GET": r = requests.get(url=api_host+request_url, params=json.loads(request_data), headers=headers) # 獲取請求狀態碼 status = r.status_code # 獲取返回值 resp = r.text if status == 200: # 斷言,判斷設置的斷言值,是否在返回值里面 if check_point in str(r.text): print("第{}條用例'{}'執行成功,狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp else: print("第{}條用例'{}'執行失敗!!!狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp else: print("第{}條用例'{}'執行失敗!!!狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp elif method == "POST": # 跟GET里面差不多,就不一一注釋了 r = requests.post(url=api_host+request_url, params=json.loads(request_data), headers=headers) status = r.status_code resp = r.text if status == 200: if check_point in str(r.text): print("第{}條用例'{}'執行成功,狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp else: print("第{}條用例'{}'執行失敗!!!狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp else: print("第{}條用例'{}'執行失敗!!!狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp else: print("第{}條用例'{}'請求方式有誤!!!請確認字段【Method】值是否正確,正確值為大寫的GET或POST。".format(num, api_name)) return 400, "請求方式有誤"
4、匯總錯誤結果、發送郵件
4.1、匯總錯誤結果,保存為簡易html報告,並通過郵件發送到指定接收人
def main(): # 執行所以測試用例,獲取錯誤的用例 error_cases = test_cases_in_excel("testcases.xlsx") # 如果有錯誤接口,則開始構造html報告 if len(error_cases) > 0: html = '<html><body>接口自動化掃描,共有 ' + str(len(error_cases)) + ' 個異常接口,列表如下:' + '</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></tr>' for test in error_cases: 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></tr>' send_email(html) print(html) with open ("report.html", "w") as f: f.write(html) else: print("本次測試,所有用例全部通過") send_email("本次測試,所有用例全部通過")
4.2、構造郵件函數
先讀取配置文件,新建config.yml配置文件,內容如下:
sender為發送郵件的郵箱,receiver為接收者着的郵箱,支持多個,smtpserver郵箱服務,username發送者郵箱少去后綴,password密碼
import yaml
def get_conf(): with open ("config.yml", "r", encoding='utf-8') as f: cfg = f.read() dic = yaml.load(cfg) sender = dic['email']['sender'] receiver = dic['email']['receiver'] smtpserver = dic['email']['smtpserver'] username = dic['email']['username'] password = dic['email']['password'] print(sender, receiver, smtpserver, username, password) return sender, receiver, smtpserver, username, password
然后構造發送郵件的函數
import smtplib
import time
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.header import Header
def send_email(text): today = time.strftime('%Y.%m.%d',time.localtime(time.time())) sender, receiver, smtpserver, username, password = get_conf() # subject為郵件主題 text為郵件正文 subject = "[api_test]接口自動化測試結果通知 {}".format(today) 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()
以上內容就將需求實現了,由於現在很晚了(懶),上面所以函數就對在一個py文件里面了,來運行下吧
郵件一會兒就收到了
所有代碼如下:

#!/usr/bin/env python #-*- coding:utf-8 -*- ''' 需求:自動讀取、執行excel里面的接口測試用例,測試完成后,返回錯誤結果並發送郵件通知。 一步一步捋清需求: 1、設計excel表格 2、讀取excel表格 3、拼接url,發送請求 4、匯總錯誤結果、發送郵件 ''' import xlrd import os import requests import json import yaml import smtplib import time import sys from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.base import MIMEBase from email.header import Header def test_cases_in_excel(test_case_file): test_case_file = os.path.join(os.getcwd(), test_case_file) # 獲取測試用例全路徑 如:E:\Python\httprunner\interface_excel\testcases.xlsx print(test_case_file) if not os.path.exists(test_case_file): print("測試用例excel文件存在或路徑有誤!") # 找不到指定測試文件,就退出程序 os.system("exit")是用來退出cmd的 sys.exit() # 讀取excel文件 test_case = xlrd.open_workbook(test_case_file) # 獲取第一個sheet,下標從0開始 table = test_case.sheet_by_index(0) # 記錄錯誤用例 error_cases = [] # 一張表格讀取下來,其實就像個二維數組,無非是讀取第一行的第幾列的值,由於下標是從0開始,第一行是標題,所以從第二行開始讀取數據 for i in range(1, table.nrows): num = str(int(table.cell(i, 0).value)).replace("\n", "").replace("\r", "") api_name = table.cell(i, 1).value.replace("\n", "").replace("\r", "") api_host = table.cell(i, 2).value.replace("\n", "").replace("\r", "") request_url = table.cell(i, 3).value.replace("\n", "").replace("\r", "") 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", "") check_point = table.cell(i, 7).value.replace("\n", "").replace("\r", "") print(num, api_name, api_host, request_url, method, request_data_type, request_data, check_point) try: # 調用接口請求方法,后面會講到 status, resp = interface_test(num, api_name, api_host, request_url, method, request_data_type, request_data, check_point) if status != 200 or check_point not in resp: # append只接收一個參數,所以要講四個參數括在一起,當一個參數來傳遞 # 請求失敗,則向error_cases中增加一條記錄 error_cases.append((num + " " + api_name, str(status), api_host + request_url)) except Exception as e: print(e) print("第{}個接口請求失敗,請檢查接口是否異常。".format(num)) # 訪問異常,也向error_cases中增加一條記錄 error_cases.append((num + " " + api_name, "請求失敗", api_host + request_url)) return error_cases def interface_test(num, api_name, api_host, request_url, method, request_data_type, request_data, check_point): # 構造請求headers 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' } # 判斷請求方式,如果是GET,則調用get請求,POST調post請求,都不是,則拋出異常 if method == "GET": r = requests.get(url=api_host+request_url, params=json.loads(request_data), headers=headers) # 獲取請求狀態碼 status = r.status_code # 獲取返回值 resp = r.text if status == 200: # 斷言,判斷設置的斷言值,是否在返回值里面 if check_point in str(r.text): print("第{}條用例'{}'執行成功,狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp else: print("第{}條用例'{}'執行失敗!!!狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp else: print("第{}條用例'{}'執行失敗!!!狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp elif method == "POST": # 跟GET里面差不多,就不一一注釋了 r = requests.post(url=api_host+request_url, params=json.loads(request_data), headers=headers) status = r.status_code resp = r.text if status == 200: if check_point in str(r.text): print("第{}條用例'{}'執行成功,狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp else: print("第{}條用例'{}'執行失敗!!!狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp else: print("第{}條用例'{}'執行失敗!!!狀態碼為{},結果返回值為{}.".format(num, api_name, status, r.text)) return status, resp else: print("第{}條用例'{}'請求方式有誤!!!請確認字段【Method】值是否正確,正確值為大寫的GET或POST。".format(num, api_name)) return 400, "請求方式有誤" def main(): # 執行所以測試用例,獲取錯誤的用例 error_cases = test_cases_in_excel("testcases.xlsx") # 如果有錯誤接口,則開始構造html報告 if len(error_cases) > 0: # html = '<html><body>接口自動化掃描,共有 ' + str(len(error_cases)) + ' 個異常接口,列表如下:' + '</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>' html = '<html><body>接口自動化掃描,共有 ' + str(len(error_cases)) + ' 個異常接口,列表如下:' + '</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></tr>' for test in error_cases: # 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>' 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></tr>' send_email(html) print(html) with open ("report.html", "w") as f: f.write(html) else: print("本次測試,所有用例全部通過") send_email("本次測試,所有用例全部通過") def get_conf(): with open ("config.yml", "r", encoding='utf-8') as f: cfg = f.read() dic = yaml.load(cfg) # print(type(dic)) # print(dic) sender = dic['email']['sender'] receiver = dic['email']['receiver'] smtpserver = dic['email']['smtpserver'] username = dic['email']['username'] password = dic['email']['password'] print(sender, receiver, smtpserver, username, password) return sender, receiver, smtpserver, username, password def send_email(text): today = time.strftime('%Y.%m.%d',time.localtime(time.time())) sender, receiver, smtpserver, username, password = get_conf() # subject為郵件主題 text為郵件正文 subject = "[api_test]接口自動化測試結果通知 {}".format(today) 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() if __name__ == "__main__": # send_email("test") main()
思考:
需要改進的地方有很多:
1、增加日志:導入logging模塊,代碼里面的print一通copy即可,自己嘗試哈
2、回寫excel表格:xlrd既然可以讀取excel文檔,肯定可以寫入的。可以新增一列,每次執行完用例,將結果寫進去,自己去嘗試哈
3、request data type沒有做判斷,這里偷懶了,因為只用了一個接口,而且大晚上在趕工,就沒有做判斷。可以參照判斷請求方式(get/post)來寫。
4、報告渣:1、可以嘗試使用htmlreport庫;2、也可以自己嘗試使用一些前端框架生成,如bootstrap
5、未做持續集成:什么是持續集成?聽起來高大上,說白了就是找個數據庫或者其他玩意兒,將用例、執行結果等等,都存儲起來。python有很多庫,可以連接各種數據庫(mysql、mongoDB),讀取excel或者其他接口腳本文檔,存入數據庫;然后請求接口后,再從庫里面讀取出來。balabala......
6、無界面:沒有界面,其實要不要都無所謂,畢竟只要維護一份excel表格即可。如果一定要的話,可以考慮使用django或者flask框架,構造web頁面,將用例的導入導出、新增、編輯、發送請求,生成報告等等一系列操作,全部移交到前端。這就需要懂一點前端代碼,如果有興趣,你也可以嘗試。
最后,這篇文章其實是借鑒(抄襲)別人的,原文地址為:https://testerhome.com/topics/4948
本文章在博客留有備份,不對,微信公眾號的才是備份,你不知道編輯公眾號的文章是多么痛苦的一件事,但既然說了,要做,再難也要搞下去不是。
我的公眾號:Python萬事屋