什麼是自動化:就是寫代碼幫你測試,原來你測試都是手動點點點,如今你寫代碼來幫你點點點。git
一.自動化框架redis
能夠理解爲工具的集合,把平常所須要實現功能的代碼,模塊進行封裝起來結合其餘的工具進行測試。得出結論報告。數據庫
二.作自動框架步驟:json
1.讀取excel 獲取用例,數組
2.解析用例session
3.解析返回結果進行對比,檢查是否經過仍是失敗app
4.把返回的結果寫入excel框架
5.生成報告,發郵件dom
三.搭建自動化框架ide
框架目錄結構:
excel用例表格:
import os,sys BAE_PATH = os.path.dirname( os.path.dirname(os.path.abspath(__file__)) ) #atp的目錄 sys.path.insert(0,BAE_PATH) from conf.setting import CASE_PATH from core import case_operation,parse_param,parse_response from core import tools import glob #glob文件路徑查詢 class RunCase: content = ''' 各位好! 本次測試結果:總共運行%s條用例,經過%s條,失敗%s條。詳細信息見附件。 ''' def get_excel(self): #s='/Users/nhy/test*.xls' for excel in glob.glob(os.path.join(CASE_PATH,'test*.xls')): cases = case_operation.get_case(excel)#調用讀取excel的函數 results = self.send_requests(cases) #發送請求,並校驗結果 report_file_path = tools.write_res(excel,results)#寫入結果 all_count = len(cases) #總共多條用例 fail_count = all_count - self.success_count content = self.content%(all_count,self.success_count,fail_count) tools.send_mail(content,report_file_path) def send_requests(self,cases): # #[[url,get,data,check],[url,get,data,check]] self.success_count = 0 results = [] for case in cases: url,method,param,check = case #獲取到每條用例的參數 p = parse_param.ParseParam(param) #解析請求參數 data = p.strToDict()#請求參數轉成字典 response = case_operation.send_request(url,method,data)#發請求 #下面這2行代碼是判斷用例執行是否經過的 p2 = parse_response.ResponseParse(response,check) status, msg = p2.check_res()#調用寫好的校驗結果方法, real_res = str(response)+'\n'+msg #是把校驗的信息和返回的json拼到一塊兒 results.append([real_res,status]) #這裏面的小list是每個用例運行的結果 if status == '經過': self.success_count += 1 #統計成功的次數 return results #返回運行的結果 def main(self): print('開始測試'.center(50,'*')) self.get_excel() print('測試結束'.center(50,'*')) if __name__ == '__main__': run = RunCase() run.main()
用例讀取,判斷請求方式
import xlrd from core.my_requests import MyRequest def get_case(path): ''' :param path: excel測試用例 :return: 二維數組,每個裏面是一條測試用例 ''' all_case = [] book = xlrd.open_workbook(path) sheet = book.sheet_by_index(0) for i in range(1,sheet.nrows): row_data = sheet.row_values(i)[4:8] all_case.append(row_data) #[[url,get,data,check],[url,get,data,check]] return all_case def send_request(url,method,data,headers=None): req = MyRequest(url,data,headers=headers) if method.upper()=="POST": res = req.post() elif method.upper() =='GET': res = req.get() else: res = {"data":"暫時不支持該方法!"} return res['data']
文件配置
import requests import nnlog from conf.setting import LOG_PATH import os BAE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #atp的目錄 LOG_PATH = os.path.join(BAE_PATH,'logs') #log目錄 CASE_PATH = os.path.join(BAE_PATH,'cases') #case目錄 REPORT_PATH = os.path.join(BAE_PATH,'report') #report目錄 CORE_PATH = os.path.join(BAE_PATH,'core') #core目錄 MAIL_INFO = { 'user':'xxxx@qq.com', 'password':'sdfsdf', 'host':'smtp.qq.com', 'smtp_ssl':True,#發件箱是qq郵箱的話,改爲True } TO = ['511402865@qq.com','496647026@qq.com','649623416@qq.com','ray-zuo@qq.com']
URL獲取參數進行解析
import requests import nnlog import os from conf.setting import LOG_PATH class MyRequest: log_file_name = os.path.join(LOG_PATH,'MyRequest.log')#日子文件名 time_out = 10 #請求超時時間 def __init__(self,url,data=None,headers=None,file=None): self.url = url self.data = data self.headers = headers self.file = file def post(self): try: req = requests.post(self.url,data=self.data,headers=self.headers, files=self.file,timeout=self.time_out) except Exception as e: res = {"status":0,"data":e.args} #0表明請求失敗 else: try: res = {"status":1,"data":req.json()} #1表明返回的json except Exception as e: res = {"staus":2,"data":req.text} #2表明返回不是json log_str = 'url: %s 請求方式:post data:%s ,返回數據:%s'%(self.url,self.data,res) self.write_log(log_str) return res def get(self): try: req = requests.get(self.url,params=self.data,headers=self.headers,timeout=self.time_out) except Exception as e: res = {"status":0,"data":e.args} #0表明請求失敗 else: try: res = {"status":1,"data":req.json()} #1表明返回的json except Exception as e: res = {"staus":2,"data":req.text} #2表明返回不是json log_str = 'url: %s get請求 data:%s ,返回數據:%s'%(self.url,self.data,res) self.write_log(log_str) return res @classmethod def write_log(cls,content): log = nnlog.Logger(cls.log_file_name) log.debug(content)
解析請求數據
import random import string import time class ParseParam: #這個類是用來解析請求參數的 func_map = ['phone','email','id_card','cur_time','money'] #映射函數的 def __init__(self,param): self.param = param self.parse() def phone(self): phone_starts = ['134','181','138','177','150','132','188','186','189','130','170','153','155'] start = random.choice(phone_starts) end = str(random.randint(0,99999999)) res = start+ end.zfill(8) return res def email(self): email_end=['163.com','qq.com','126.com','sina.com'] end = random.choice(email_end) start_str='ATP_test_' email_start = ''.join(random.sample(string.ascii_letters+string.digits,6)) return start_str+email_start+'@'+end '''def id_card(self): #這個產生身份證號的 return 410881199011212121 def cur_time(self): return int(time.time()) def order_id(self): #從數據庫裏面獲取 pass def session_id(self): #從redis裏面獲取的 pass def money(self): return 10000 ''' def parse(self): for func in self.func_map: temp = str(getattr(self,func)()) #手機號 self.param = self.param.replace('<%s>'%func,temp) def strToDict(self): #這個函數是把請求參數轉成字典的 data ={} pl = self.param.split(',') for p in pl: temp = p.split('=') if len(temp)>1: key,value = temp data[key] = value return data if __name__ == '__main__': param = 'username=niuhanyang' \ ',phone=<phone>,email=<email>' \ ',id_card=<id_card>,start_time=' \ '<cur_time>,balan=<money>' p = ParseParam(param) data = p.strToDict() print(data) '''print(p.phone()) # res = getattr(p,'money') #獲取一個對象裏面的屬性(方法、變量) # # print(res()) # import os,requests # res = hasattr(requests,'get')#判斷某個模塊、類下面有沒有某個方法或者變量 # print(res) 用例的支持參數化,支持如下參數化: <phone> 自動產生手機號 <id_card> 身份證號 <email> 郵箱 <cur_time> 當前時間戳 '''
校驗檢查點
import jsonpath class ResponseParse: seqs = ['!=', '>=', '<=', '=', '<', '>', 'in', 'notin'] #定義支持的運算符 def __init__(self,response,check): self.response = response self.check = check #進行解析 校驗結果,預期結果 def format_check(self): #格式化檢查信息,分別列出key 運算符 實際結果 #會返回 [['error_code','=','0'],['name','!=','xxx']] format_list = [] check_list = self.check.split(',') for s in check_list: for seq in self.seqs: if seq in s: if len(s.split(seq))>1: key, value = s.split(seq) temp = [key, seq, value] format_list.append(temp) break return format_list #1.檢查點解析完成 def get_real_value(self,key): #從字典裏面獲取key對應的value res = jsonpath.jsonpath(self.response,'$..%s'%key) #$..%s這個是jsonpath這個模塊的用法 if res: return res[0] return '找不到該key【%s】'%key #2.取得實際的值 def operation_check(self,real,seq,hope): #根據運算符判斷結果(實際結果,運算符,預期結果) msg = "判斷信息:%s %s %s "%(real,seq,hope) real = str(real)#爲了保持類型一致 if seq=='=': status = real == hope elif seq=='!=': status = real != hope elif seq =='in': status = real in hope elif seq =='notin': status = real not in hope else: status,msg = self.num_check(real,seq,hope) return status,msg def num_check(self,real,seq,hope): #判斷數值類型的 msg = "判斷信息:%s %s %s "%(real,seq,hope) try: real=float(real) hope=float(hope) except Exception as e: msg = "比較時出錯,大小比較只能是數字類型!" \ "%s %s %s"%(real,seq,hope) status = False else: if seq=='>': status = real > hope elif seq =='<': status = real < hope elif seq == '<=': status = real <= hope else: status = real >= hope return status,msg def check_res(self): #校驗全部的檢查點 check_list = self.format_check() all_msg='' for check in check_list:#循環全部的檢查點 key,seq,hope = check real = self.get_real_value(key) status,msg = self.operation_check(real,seq,hope) all_msg = all_msg+msg+'\n' #累加提示信息 if status: pass else: return '失敗',all_msg return '經過',all_msg
產生excel文件寫入校驗結果
import xlrd from xlutils.copy import copy import os import datetime from conf import setting import yagmail def make_today_dir(): #建立當天的文件夾,返回絕對路徑 today = str(datetime.date.today()) #c:/xxx/xxx/atp/report/2018-11-24/測試用例.xls abs_path = os.path.join(setting.REPORT_PATH,today) #拼成當天的絕對路徑 if os.path.exists(abs_path): pass else: os.mkdir(abs_path) return abs_path def write_res(case_path,case_res): #c:/xxx/xxx/atp/cases/測試用例.xls #[ ['{"xdfsdf}','經過'],['{"xdfsdf}','失敗'] ] book = xlrd.open_workbook(case_path) new_book = copy(book) sheet = new_book.get_sheet(0) for row,res in enumerate(case_res,1): response,status = res sheet.write(row,8,response) sheet.write(row,9,status) #寫第8列和第9列 cur_date_dir = make_today_dir()#建立當前文件夾,而且返回絕對路徑 file_name = os.path.split(case_path)[-1] #只獲取到filename cur_time = datetime.datetime.today().strftime('%H%M%S') #獲取到當天時分秒 new_file_name = cur_time+'_'+file_name #165530_測試用例.xls real_path = os.path.join(cur_date_dir,new_file_name)#拼路徑 new_book.save(real_path) return real_path def send_mail(content,file_path=None): #發郵件,傳入郵件正文和附件 m = yagmail.SMTP(**setting.MAIL_INFO,) subject = '接口測試報告_%s'%str(datetime.datetime.today()) m.send(subject=subject,to=setting.TO,contents=content,attachments=file_path)