原文鏈接:http://www.cnblogs.com/Detector/p/6935650.html
實現思路
使用excel管理用例用例信息,requests模塊發送http請求,實現了記錄日誌,郵件發送測試報告的功能
目錄結構如下:
D:\PROJECT\INTERFACE_
│ controler.py
│ interface.py
│ logging_save.py
│ result_check.py
│ result_save.py
│ result_send.py
│ testcase_get.py
│ url_transform.py
│ __init__.py
├─config
│ config.py
│ mail.conf
│ __init__.py
│
├─report
│ [email protected]@163850.xls
│ __init__.py
│
└─test_case
20170602.xls
__init__.py
下面直接上代碼:
controler.py 統籌執行所有腳本
# -*- coding:utf-8 -*- from interface import Interface from testcase_get import Get_testcase from result_save import Save_test_result from result_send import Send_report from config.config import Config from logging_save import logger import os if __name__ == '__main__': '''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!''' cur_path = os.path.split(os.path.realpath(__file__))[0] #獲取當前文件絕對路徑 case_path = os.path.join(cur_path,'test_case','20170602.xls') test_case = Get_testcase(case_path).readExcel() #獲取用例 if not isinstance(test_case,list): #判斷用例是否獲取成功 logger.info('Test_case get failed... \n Done!') else: logger.info('獲取用例成功') # 調用接口 test_result = Interface().interfaceTest(test_case) #獲取執行結果,用於發郵件 count_success = test_result[3] count_failure = test_result[4] failed_case_detail = test_result[5] # 保存測試結果 Save_test_result().save_result(case_path, test_result[0], test_result[1], test_result[2]) logger.info('保存測試結果成功') #獲取郵件配置信息 mail_config = Config(os.path.join(cur_path,'config', 'mail.conf')).get_mail_config() logger.info('獲取郵箱配置成功') login_user = mail_config[0] login_pwd = mail_config[1] from_addr = mail_config[2] to_addrs = mail_config[3] smtp_server = mail_config[4] mail_send = Send_report(count_success, count_failure, failed_case_detail) #獲取最新測試報告 last_report = mail_send.newest_report() mail_send.send_result(login_user, login_pwd,from_addr, to_addrs,smtp_server,last_report)
interface.py 對接口的發送和請求統一進行的封裝
#coding:utf-8 import requests,json from logging_save import logger from result_check import result_check from url_transform import urltransform class Interface(): def __init__(self,): pass def interfaceTest(self,case_list): ''' 接口調用主函數 ''' # 用於存結果 res_flags = [] # 用於存請求報文 request_urls = [] # 用於存返回報文 responses = [] #用戶存失敗的用例 failed_case = [] #統計成功失敗的用例數 count_success = 0 count_failure = 0 for case in case_list: try: # 模塊 product = case[0] # 用例id case_id = case[1] # 用例標題 interface_name = case[2].strip('\n') # 用例描述 case_detail = case[3] # 請求方式 method = case[4] # 請求url url = case[5] # 入參 param = case[6] # 預期結果 res_check = case[7] except Exception, e: return '測試用例格式不正確!%s' % e # 定義消息頭信息 headers = {'content-type': 'application/json', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0'} #對url進行封裝 new_url = urltransform().urltransform(url,method,param) if method.upper() == 'GET': results = requests.get(new_url).text #print results responses.append(results) #用於存儲預期結果與實際結果的比較結果 res = result_check().result_check(results, res_check) request_urls.append(new_url) else: request_urls.append(new_url) if param == '': pass else: data = json.loads(param) #將參數轉化爲json格式 results = requests.post(new_url,data=json.dumps(data),headers=headers).text responses.append(results) res = result_check().result_check(results, res_check) if 'pass' in res: res_flags.append('pass') count_success += 1 else: logger.warning(u'接口: %s 調用失敗'%interface_name) logger.warning(u'失敗接口URL: %s METHOD :%s'%(url,method)) res_flags.append('fail') count_failure += 1 failed_case.append((interface_name,method,url)) return res_flags,request_urls,responses,count_success,count_failure,failed_case #print request_urls,res_flags,responses
logging_save.py 對日誌模塊統一進行的封裝,可以保存日誌和在控制檯輸出
# coding=utf-8 import logging import sys import traceback import time class LoggingUtils: ''' ===========封裝日誌工具類的基本操作============= ''' def __init__(self,logfile): ''' :param logfile: ''' self.logger = logging.getLogger(logfile) self.hdlr = logging.FileHandler(logfile) formatter = logging.Formatter('%(asctime)s %(levelname)s - %(message)s') self.ch = logging.StreamHandler() self.ch.setLevel(logging.INFO) self.ch.setFormatter(formatter) self.hdlr.setFormatter(formatter) self.logger.addHandler(self.hdlr) self.logger.addHandler(self.ch) self.logger.setLevel(logging.DEBUG) def debug(self, msg): ''' :param msg: :return: ''' self.logger.debug(msg) self.hdlr.flush() def info(self, msg): ''' :param msg: :return: ''' self.logger.info(msg) self.hdlr.flush() def warning(self,msg): self.logger.warning(msg) self.hdlr.flush() def error(self, msg): ''' :param msg: :return: ''' self.logger.error(msg) # self.logger.removeHandler(logging.StreamHandler()) self.logger.removeHandler(self.ch) self.hdlr.flush() def error_sys(self, limit=None): ''' :param limit: :return: ''' exceptionType, exceptionValue, exceptionTraceback = sys.exc_info() if limit is None: if hasattr(sys, 'tracebacklimit'): limit = sys.tracebacklimit n = 0 eline = '\n' while exceptionTraceback is not None and (limit is None or n < limit): f = exceptionTraceback.tb_frame lineno = exceptionTraceback.tb_lineno co = f.f_code filename = co.co_filename name = co.co_name eline += ' File "%s", line %d, in %s \n ' % (filename, lineno, name) exceptionTraceback = exceptionTraceback.tb_next n = n + 1 eline += "\n".join(traceback.format_exception_only(exceptionType, exceptionValue)) self.logger.error(eline) self.hdlr.flush() timer = time.strftime('%Y-%m-%d',time.localtime()) logger = LoggingUtils('%s.log'%timer)
result_check.py 進行測試結果比對的模塊,可以根據項目情況進行擴展
#coding:utf-8 class result_check(): def __init__(self): pass def result_check(self,results,res_check): ''' 結果對比函數 ''' #返回結果,將結果中的json數據轉化爲可以和預期結果比較的數據 res = results.replace('":"','=').replace('" : "','=') #預期結果,是xx=11;xx=22 res_check = res_check.split(';') for s in res_check: if s in res: pass else: return '結果不匹配 '+ str(s) return 'pass'
result_save.py 保存測試結果的模塊,複製原有的用例,保存爲新的excel
#coding:utf-8 from xlutils import copy import xlrd import time import os class Save_test_result(): def __init__(self): pass def save_result(self,file_path,res_flags,request_urls,responses): ''' :return: ''' book = xlrd.open_workbook(file_path) new_book = copy.copy(book) sheet = new_book.get_sheet(0) i = 1 for request_url, response, flag in zip(request_urls, responses, res_flags): sheet.write(i, 8, u'%s' % request_url) sheet.write(i, 9, u'%s' % response) sheet.write(i, 10, u'%s' % flag) i += 1 report_path = os.path.abspath(os.path.join('report')) if not os.path.exists(report_path): os.makedirs(report_path) new_book.save(os.path.abspath(os.path.join(report_path, 'Report@%s.xls' % time.strftime('%Y.%m.%d@%H%M%S'))))
result_send.py 發送郵件的模塊,可以發送多個附件
#coding:utf-8 import smtplib from email.mime.text import MIMEText from email.header import Header from email.mime.multipart import MIMEMultipart import os from logging_save import logger class Send_report(object): def __init__(self,count_success,count_failure,failed_case): ''' :param count_success: :param count_failure: :param failed_case: ''' self.count_success = count_success self.count_failure = count_failure self.failed_case = failed_case def newest_report(self,testreport='report'): ''' 獲取最新的測試報告 :param testreport: :return: ''' lists = os.listdir(testreport) lists.sort(key=lambda fn: os.path.getmtime(os.path.join(testreport,fn))) file_new = os.path.join(testreport, lists[-1]) logger.info('獲取最新附件報告成功') return file_new def send_result(self,username,passwd,from_addr,to_addrs,smtpserver,*args): ''' :param username: :param passwd: :param from_addr: :param to_addrs: :param smtpserver: :param args: :return: ''' sender = from_addr subject = '財富港接口測試結果' username = username passwd = passwd '''郵件內容''' tille = (u'用例名稱', u'請求方式', u'url') details = (u'成功: ' + str(self.count_success) + u'失敗: ' + str(self.count_failure)) + '\n' + u'失敗的用例如下 :' + \ '\n' + '\n'.join(str(zip(tille, i)) for i in self.failed_case).decode('unicode-escape') logger.info('郵件附件爲: %s' %(args[0].split('\\')[1])) if args != None: #判斷是否添加附件 msg = MIMEMultipart() msg.attach(MIMEText(details, 'plain', 'utf-8')) i = 0 while i < len(args): #可以添加多個附件 part = MIMEText(open(args[i], 'rb').read(), 'base64', 'utf-8') part["Content-Type"] = 'application/octet-stream' part["Content-Disposition"] = 'attachment; filename="%s"'%args[i] msg.attach(part) #添加附件 i += 1 msg['subject'] = Header(subject, 'utf-8') msg['From'] = from_addr msg['To'] = ','.join(eval(to_addrs)) #兼容多個收件人 smtp = smtplib.SMTP() try: smtp.connect(smtpserver) smtp.login(username, passwd) smtp.sendmail(sender, eval(to_addrs), msg.as_string()) smtp.close() logger.info('帶附件測試報告發送成功!') except smtplib.SMTPAuthenticationError,e: logger.error('郵箱賬戶或密碼錯誤: '+ str(e)) else: msg = MIMEText(details, 'plain', 'utf-8') msg['subject'] = Header(subject, 'utf-8') msg['From'] = from_addr msg['To'] = ','.join(eval(to_addrs)) smtp = smtplib.SMTP() try: smtp.connect(smtpserver) smtp.login(username, passwd) smtp.sendmail(sender, eval(to_addrs), msg.as_string()) logger.info('測試報告發送成功!') smtp.close() except smtplib.SMTPAuthenticationError,e: logger.error('郵箱賬戶或密碼錯誤 : '+str(e))
testcase_get.py 獲取用例信息的模塊
#coding:utf-8 import xlrd from logging_save import logger class Get_testcase(object): def __init__(self, file_path): ''' :param file_path: 用例文件路徑 ''' self.file_path = file_path def readExcel(self): ''' 讀取用例函數 :return: 測試用例列表 ''' try: book = xlrd.open_workbook(self.file_path) # 打開excel except Exception, error: logger.error('路徑不在或者excel不正確 : ' + str(error)) return error else: sheet = book.sheet_by_index(0) # 取第一個sheet頁 rows = sheet.nrows # 取這個sheet頁的所有行數 case_list = [] # 用於保存用例信息 for i in range(rows): if i != 0: case_list.append(sheet.row_values(i)) # 把每一條測試用例添加到case_list中 return case_list
url_transform.py 對excel中管理的請求的url進行轉換的模塊
#coding:utf-8 class urltransform(object): def __init__(self): pass def urltransform(self, url, method, param): ''' :return: ''' if param == '': new_url = url else: if method.upper() == 'GET': new_url = url + '?' + param.replace(';', '&') #如果有參數,且爲GET方法則組裝url else: new_url = url return new_url
testcase目錄下excel結構
config目錄下,config.py 獲取配置文件信息的模塊
#conding:utf-8 import ConfigParser class Config(object): def __init__(self,file_path): self.config = ConfigParser.ConfigParser() self.config.read(file_path) def get_mail_config(self): login_user = self.config.get('SMTP', 'login_user') login_pwd = self.config.get('SMTP', 'login_pwd') from_addr = self.config.get('SMTP', 'from_addr') to_addrs = self.config.get('SMTP', 'to_addrs') smtp_server = self.config.get('SMTP', 'smtp_server') port = self.config.get('SMTP', 'port') return login_user, login_pwd , from_addr, to_addrs,smtp_server, port def report_save_config(self): pass
mail.conf
[SMTP] login_user = 18******@163.com login_pwd = ****** from_addr = BI<18******@163.com> to_addrs = ['18******@163.com'] #to_addrs = ['1******@qq.com','******.com'] smtp_server = smtp.163.com port = 25
報告效果圖
收到的郵件效果圖: