三.介面自動化專案1

少壮不努力123發表於2024-03-09
一.介面自動化需求分析:
介面自動化測試用例:
1.用例寫在excel表格裡面,定義函式獲取excel表格中資料並加入到用例列表
中進行返回
a.Excel表格中的資料只有url/請求方式、請求引數、headers、是否json、
預期結果才是有效資料
b.請求引數定義格式是"xxx=123,sss>456,phone=<phone>"這種的,需要
轉換成字典的形式,並且<phone>需要進行引數化
c.headers請求頭需要轉換成字典
2.用例讀取完成後,需要進行傳送請求,需要構造一個請求的函式,請求成功後返
回請求結果json格式和字串格式的結果
3.拿到請求結果後,需要對預期結果和實際結果進行比對,只要有一條資料不透過
就失敗
4.最後進行串聯整個流程
a.先讀取測試用例檔案大,獲取所有測試用例excel檔案
b.執行測試用例,
先根據excel檔案獲取到所有測試用例;
再迴圈測試用例並進行介面請求,獲取到介面返回的結果;
然後根據結果返回的實際結果與預期結果進行比較,並把執行總條數、成功數、狀態、失敗原因放在列表中儲存在response_list中;
最後把執行結果寫入到excel表格中
c.最後傳送介面測試用例執行結果報告郵件
二.進行介面自動化專案程式定義分類:
1.建立一個AutoTestProject資料夾後並在該資料夾下分別建立bin、case、config、lib、logs、report資料夾,bin目錄做完程式的入口目錄並在下面建立start.py檔案;case目錄用來存放結果自動化測試用例;config用來存放配置檔案及自動化測試用例模板檔案;lib資料夾下存放read_case.py、request.py、parse_response.py、utils.py等資料夾;logs資料夾用來存放日誌的;report資料夾用來存放測試報告的

2.在case檔案目錄下存放測試用例檔案,測試用例以test開頭和xls或xlsx結尾

3.config資料夾下定義配置相關內容及模板檔案
setting.py檔案
三.介面自動化專案1
import os
import random
import string

import faker


# 傳送郵件
EMAIL_INFO={
    "user":"13424210282@163.com",
    "password":"HLXWWGTUWGNAAAEA",
    "host":"smtp.163.com",
}
# 郵件接收人
T0=["974219141@qq.com"]
# 郵件抄送人
CC=['751462075@qq.com']

# 介面請求url地址配置
host_map={
    "fat":"http://127.0.0.1:8787",
    "uat":"",
    "pro":""
}
default="fat"

HOST=host_map.get(default)

# 自動化專案父目錄
BASE_PATH=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 測試用例目錄
CASE_PATH=os.path.join(BASE_PATH,'case')
# 日誌檔案目錄
LOG_PATH=os.path.join(BASE_PATH,"logs",'atp.log')
# 測試報告目錄
REPORT_PATH=os.path.join(BASE_PATH,'report')

# faker.Faker生成資料進行引數化
f=faker.Faker(locale="zh-CN")

"""
進行引數化的字典,後續有欄位數值需要進行引數化的時候只需要在這裡進行維護
"""
def getPassword():
    """
    生成隨機密碼的
    :return:
    """
    a=random.sample(string.digits,2)
    b=random.sample(string.ascii_uppercase,2)
    c=random.sample(string.ascii_lowercase,2)
    d=random.sample("@#$%^&*",2)
    s=a+b+c+d
    # 資料清洗或打亂
    random.shuffle(s)
    return "".join(s)

func_map={
    "<phone>":f.phone_number,
    "<id_card>":f.ssn,
    "<email>":f.email,
    "<name>":f.name,
    "<addr>":f.address,
    "<password>":getPassword
}

import nnlog
LOG=nnlog.Logger(LOG_PATH)
View Code
4.lib檔案下定義utils.py進行發郵件、獲取字典中的值、寫報告功能;read_case.py定義獲取用例列表;request.py定義傳送請求;parse_response.py定義結果比對
A.utils.py
三.介面自動化專案1
from xlutils import copy
import os
import random
import string
import time
import traceback

import yagmail

from config.setting import REPORT_PATH,LOG,EMAIL_INFO,T0,CC
import jsonpath
import xlrd


def get_value(d,k):
    # 透過jsonpath.jsonpath來取字典中key所對應的值
    result=jsonpath.jsonpath(d,'$..%s'%k)
    # 如果取到了返回第一個值,否則返回空字串
    if result:
        return result[0]
    return ''

"""
result_list=[
    [{"code":0,"msg":"成功"},"透過"],
    [{"code":0,"msg":"成功"},"失敗"],
]
"""

def write_excel(file_name,result_list):

    """
    result_list存放用例執行結果["引數","執行結果","原因","狀態"]
    :param file_name:
    :param result_list:
    :return:
    """
    LOG.debug("現在開始寫報告了:檔名是%s,內容是%s"%(file_name,result_list))
    book=xlrd.open_workbook(file_name)
    newbook=copy.copy(book)
    try:
        sheet=newbook.get_sheet(0)
    except Exception as e:
        print("無法開啟excel=============",file_name)
    for row,result in enumerate(result_list,1):
        for col ,value in enumerate(result[1:],7):
            sheet.write(row,col,value)
        sheet.write(row,3,result[0])
    file_name=os.path.split(file_name)[-1].replace("xlsx","xls")
    new_file_name=time.strftime("%Y%m%d%H%M%S")+"_"+file_name
    case_file=os.path.join(REPORT_PATH,new_file_name)
    newbook.save(case_file)
    LOG.debug("報告生成完成,檔名是%s"%(case_file))
    return case_file


def send_email(all_count,pass_count,file_name):
    LOG.debug("開始傳送報告了,檔名是%s"%file_name)
    content='''
各位好:
    本次介面自動化測試結果如下,總共執行%s條用例,透過%s條,失敗【%s】條。
    詳情請檢視附件。
    '''%(all_count,pass_count,(all_count-pass_count))

    subject='%s-介面測試報告'%time.strftime("%Y-%m-%d %H%M%S")

    email=yagmail.SMTP(**EMAIL_INFO,encoding="GBK")

    try:
        email.send(to=T0,cc=CC,subject=subject,contents=content,attachments=file_name)
    except Exception as e:
        LOG.error("傳送報告失敗,具體失敗原因是%s"%traceback.format_exc())
    else:
        LOG.debug("報告傳送成功")
View Code
B.read_case.py
三.介面自動化專案1
import nnlog
import traceback
import xlrd
from config.setting import LOG_PATH,func_map
import jsonpath

log=nnlog.Logger(LOG_PATH)

# "$..key"是進行模糊查詢
# jsonpath.jsonpath(d,"$..key")
# faker模板的使用

class ParamDeal():

    def read_excel(self,file_path):
        # case_list存放測試用例
        case_list=[]
        try:
            # 開啟excel
            book=xlrd.open_workbook(file_path)
            sheet=book.sheet_by_index(0)
            #
            for row in range(1,sheet.nrows):
                # 只取有用的那幾行
                line=sheet.row_values(row)[1:7]

                # 把引數先進行替換
                line[2]=self.replace_param(line[2])

                # 將header轉換成字典
                line[3]=self.replace_param(line[3])
                # 再把引數進行轉換成字典
                line[2]=self.str_to_dict(line[2])

                line[3]=self.str_to_dict(line[3])
                case_list.append(line)
        except Exception as e:
            log.error("讀取檔案出錯,檔名是:%s"%file_path)
            log.error("具體的錯誤資訊是%s"%traceback.format_exc())
        return case_list

    def replace_param(self,s):
        """
        進行引數替換
        :param s:
        :return:
        """
        for func_name,func in func_map.items():
            if func_name in s:
                result=func()
                s=s.replace(func_name,result)
        return s

    def str_to_dict(self,s):
        """
        字串轉換成字典,如果是空字串直接返回空字典
        :param s:
        :return:
        """
        d={}
        # 判斷引數是否為空
        if s.strip():
            # 字串透過逗號進行分割後透過等號進行分割後再轉換成字典
            for i in s.split(","):
                k,v=i.split("=")
                d[k]=v
        return d
View Code

C.request.py

三.介面自動化專案1
import traceback

import requests
from config import setting
from urllib.parse import  urljoin
import nnlog


log=nnlog.Logger(setting.LOG_PATH)
class MyRequest:
    def __init__(self,url,method,data=None,headers=None,is_json=''):
        # 拼接url,透過urljoin進行拼裝url
        self.url=urljoin(setting.HOST,url)
        self.data=data
        self.headers=headers
        self.is_json=is_json
        self.method=method.lower()
        self.req()

    def req(self):
        try:
            if self.is_json=='':
                response= requests.request(self.method,self.url,params=self.data,json=self.data,headers=self.headers).json()
            else:
                response= requests.request(self.method,self.url,params=self.data,data=self.data,headers=self.headers).json()
        except Exception as e:
            log.error("請求%s的時候出錯了,請求引數是%s,錯誤資訊是%s"%(self.url,self.data,traceback.format_exc()))
            self.result={"msg":"請求介面出錯了","error_msg":traceback.format_exc()}
            self.text='{"msg":"請求介面出錯了","error_msg":%s}'%(traceback.format_exc())
        else:
            self.result=response
            self.text=str(response)
View Code

D.parse_response.py

三.介面自動化專案1
from lib.utils import get_value
from config.setting import LOG_PATH
import nnlog

log=nnlog.Logger(LOG_PATH)

class ParseResponse:

    fuhao=['!=','>=','<=','>','<','=']

    def __init__(self,check_str,response):
        self.check_str=check_str
        self.response=response
        self.reason="都透過了"
        self.status='透過'
        self.check_response()

    def check_response(self):
        """
        預期結果格式是:yuqijieguo="status=1,score>60,age!=15"
        :return:
        """
        if self.check_str.strip():
            for s in self.check_str.split(","):
                for f in self.fuhao:
                    if f in s:
                        # 分割取出預期結果中的key
                        key, value = s.split(f)
                        # 取到實際結果
                        shijijieguo = get_value(self.response, key)
                        # 如果是實際結果型別是字串的話,實際結果和預期結果都轉換成字串進行比較
                        if type(shijijieguo) == str:
                            shijijieguo = "'%s'" % (shijijieguo)
                            value = "'%s'" % (value)

                        # 轉換成字串進行eval執行
                        f = "==" if f == "=" else f
                        code = "%s %s %s" % (shijijieguo, f, value)
                        tag=eval(code)
                        # 判斷tag不是true時表示有預期結果與實際結果對比是失敗的
                        if tag!=True:
                            self.reason='key是%s,運算的程式碼是%s'%(key,code)
                            log.debug(self.reason)
                            self.status='失敗'
                            return False
                        break
        return True
View Code
5.bin檔案下定義start.py檔案是程式主入口;duoxiancheng.py是檔案程式多執行緒執行入口
A. start.py
三.介面自動化專案1
#! /usr/bin python
#-*- encoding=utf-8 -*-

from lib.read_case import ParamDeal
from lib.request import MyRequest
from lib.parse_response import get_value,ParseResponse
from lib.utils import send_email,write_excel
import os
from config.setting import CASE_PATH


class CaseRun:
    all_count=0
    pass_count=0
    def get_case(self):
        # 獲取excel測試用例檔案
        excel_list=[]
        for file in os.listdir(CASE_PATH):
            if file.startswith("test") and (file.endswith('.xls') or file.endswith(".xlsx")):
                abs_path = os.path.join(CASE_PATH, file)
                excel_list.append(abs_path)
        return excel_list

    def run_case(self,file_name):
        read_case_obj=ParamDeal()
        # 根據excel檔案獲取其中的測試用例
        case_list=read_case_obj.read_excel(file_name)

        # response_list用於存放所有的結果
        response_list=[]

        # 迴圈用例列表進行傳送請求
        for case in case_list:
            # 統計用例的總個數,迴圈一次,用例加一條
            self.all_count+=1
            # 傳送介面請求
            req_obj=MyRequest(*case[:5])

            # 校驗結果

            response_obj=ParseResponse(case[-1],req_obj.result)

            if response_obj.status=='透過':
                # 統計用例執行個數
                self.pass_count+=1
            response_list.append([str(req_obj.data),req_obj.text,response_obj.status,response_obj.reason])
        return  write_excel(file_name,response_list)



    def main(self):
        report_list=[]
        excel_list=self.get_case()
        for excel in excel_list:
            report_name=self.run_case(excel)
            report_list.append(report_name)

        send_email(self.all_count,self.pass_count,report_list)

if __name__=="__main__":
    c=CaseRun()
    c.main()
View Code

B. duoxiancheng.py

三.介面自動化專案1
import os,sys
sys.path.insert(0,os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from lib.read_case import ParamDeal
from lib.request import MyRequest
from lib.parse_response import get_value,ParseResponse
from lib.utils import send_email,write_excel

from config.setting import CASE_PATH
import threading

class CaseRun:
    all_count=0
    pass_count=0
    report_list = []
    def get_case(self):
        # 獲取excel測試用例檔案
        excel_list=[]
        for file in os.listdir(CASE_PATH):
            if file.startswith("test") and (file.endswith('.xls') or file.endswith(".xlsx")):
                abs_path = os.path.join(CASE_PATH, file)
                excel_list.append(abs_path)
        return excel_list

    def run_case(self,file_name):
        read_case_obj=ParamDeal()
        # 根據excel檔案獲取其中的測試用例
        case_list=read_case_obj.read_excel(file_name)
        # response_list用於存放所有的結果
        response_list=[]

        # 迴圈用例列表進行傳送請求
        for case in case_list:
            # 統計用例的總個數,迴圈一次,用例加一條
            self.all_count+=1
            # 傳送介面請求
            req_obj=MyRequest(*case[:5])
            # 校驗結果
            response_obj=ParseResponse(case[-1],req_obj.result)

            if response_obj.status=='透過':
                # 統計用例執行個數
                self.pass_count+=1
            response_list.append([str(req_obj.data),req_obj.text,response_obj.status,response_obj.reason])
        report_name=  write_excel(file_name,response_list)
        self.report_list.append(report_name)



    def main(self):
        """
        啟動多執行緒執行
        :return:
        """
        excel_list=self.get_case()
        for excel in excel_list:
            t=threading.Thread(target=self.run_case,args=(excel,))
            t.start()
        while threading.active_count()!=1:
            pass

        send_email(self.all_count,self.pass_count,self.report_list)

if __name__ == '__main__':
    c=CaseRun()
    c.main()
View Code

相關文章