• python 之 自制测试框架


    叙:使用python 搭建自动化框架,适用于接口post/get 的form请求

    框架搭建思路:

    1.准备好测试用例,包含的内容有:项目名称,模块名称,用例id,用例描述,请求url,请求方式,请求数据,预期结果,请求报文,返回报文,测试结果,测试人员等

    2.梳理整个流程:

    • 读取测试用例
    • 获取用例中url+请求参数+请求方法
    • 进行接口请求,获取返回值,获取测试结果
    • 将获取的返回值,测试结果,写入测试用例中
    • 存成新的测试用例,存放在data目录下
    • 获取最新测试用例(已填写了测试结果的),并生成HTML测试报告
    • 将生成的测试报告发送邮件

    3.我搭建的框架目录结构

    代码实现如下:

    #请求接口,生成测试报告的必备小功能(tools)
    import os
    
    import requests
    import time
    import xlrd
    from xlutils import copy
    from conf.setting import DATA_PATH
    def readCase(case_path):
        case_list = [] #存放所有的测试用例,给后面运行的时候使用
        book = xlrd.open_workbook(case_path)
        sheet = book.sheet_by_index(0)
        for line in range(1,sheet.nrows):
            case = []
            line_case = sheet.row_values(line)#row_values是excel里面每一行的所有数据
            project = line_case[0]
            model = line_case[1]
            case_id = line_case[2]
            detail = line_case[3]
            url = line_case[4]
            method = line_case[5]
            req_data = line_case[6]
            hope = line_case[7]
            req_msg = line_case[8]
            response_msg = line_case[9]
            test_status = line_case[10]
            tester = line_case[11]
            case = [project,model,case_id,detail,url,method,req_data,hope,req_msg,response_msg,test_status,tester]
            case_list.append(case)
        return case_list
    
    def strToDict(data):
        #username=niuhy,passwd=123456
        dic  = {}
        data_list = data.split(',')
        # ['username=niuhy','passwod=123456']
        for k in data_list:
            #username=niuhy
            k_list = k.split('=')
            #['usenrmae','niuhy']
            dic_k = k_list[0]
            dic_v = k_list[1]
            dic[dic_k]=dic_v
        return dic
    
    def my_request(method,url,data):
        new_data = strToDict(data)
        try:
            if method.upper()=='GET':
                r = requests.get(url,new_data)
            else:
                r = requests.post(url,new_data)
        except Exception as e:
            return '出错了,错误是%s'%e
        return r.text
    
    def check_res(response,hope):
        new_response = response.replace('": "','=').replace('": ','=')
        for check in hope.split(','):
            if check not in new_response:
                return 'fail'
        return 'ok'
    
    def urlParam(param):
        return param.replace(';','&')
    
    def write_excel(src_case_path,res_list):
        src_book = xlrd.open_workbook(src_case_path)
        new_book = copy.copy(src_book)
        sheet = new_book.get_sheet(0)
        line = 1
        for res in res_list:
            req  = res[0]
            response  = res[1]
            status  = res[2]
            sheet.write(line,8,req)
            sheet.write(line,9,response)
            sheet.write(line,10,status)
            line+=1
        file_name = time.strftime('%Y%m%d%H%M%S')+os.path.basename(src_case_path)
        abs_path = os.path.join(DATA_PATH,file_name).replace('xlsx','xls')
        new_book.save(abs_path)
        return os.path.abspath(abs_path)
    
    
    if __name__ =='__main__':
        move_report()
        # res = readCase(r'C:UsersjniuhanyangDesktop测试用例.xlsx')
        # print(res)
        # dic = strToDict('username=niuhy,passwd=123456')
        # print(dic)
        # r = my_request('get','http://lanxia.lxsb.com','a=1')
        # print(r)
    #     res = """
    #     {
    #     "error_code": 0,
    #     "login_info": {
    #         "login_time": "20171216171928",
    #         "sign": "d8f3044197d21f18bf782b0f0b7e9a8b",
    #         "userId": 8
    #     }
    # }
    #     """
    #     # r = check_res(res,'error_code=0,userId=8')
    #     # print(r)
    #     res_list =[ [
    #         'http://api.nnzhp.cn/user?username=xxx&passwd=111','{}',True
    #     ]
    #     ]
    #     excel_path=r'C:UsersjniuhanyangDesktop测试用例.xlsx'
    #     write_excel(excel_path,res_list)
    #     # 总共运行了N条测试用例,通过xx条,失败xx。


    #发送邮件功能实现
    import smtplib,os
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    import base64
    class SendMail(object):
    def __init__(self,username,passwd,recv,title,content,
    file=None,ssl=False,
    email_host='smtp.qq.com',port=25,ssl_port=465):
    '''
    :param username: 用户名
    :param passwd: 密码
    :param recv: 收件人,多个要传list ['a@qq.com','b@qq.com]
    :param title: 邮件标题
    :param content: 邮件正文
    :param file: 附件路径,如果不在当前目录下,要写绝对路径,默认没有附件
    :param ssl: 是否安全链接,默认为普通
    :param email_host: smtp服务器地址,默认为163服务器
    :param port: 非安全链接端口,默认为25
    :param ssl_port: 安全链接端口,默认为465
    '''
    self.username = username #用户名
    self.passwd = passwd #密码
    self.recv = recv #收件人,多个要传list ['a@qq.com','b@qq.com]
    self.title = title #邮件标题
    self.content = content #邮件正文
    self.file = file #附件路径,如果不在当前目录下,要写绝对路径
    self.email_host = email_host #smtp服务器地址
    self.port = port #普通端口
    self.ssl = ssl #是否安全链接
    self.ssl_port = ssl_port #安全链接端口
    def send_mail(self):
    msg = MIMEMultipart()
    #发送内容的对象
    if self.file:#处理附件的
    file_name = os.path.split(self.file)[-1]#只取文件名,不取路径
    try:
    f = open(self.file, 'rb').read()
    except Exception as e:
    raise Exception('附件打不开!!!!')
    else:
    att = MIMEText(f,"base64", "utf-8")
    att["Content-Type"] = 'application/octet-stream'
    #base64.b64encode(file_name.encode()).decode()
    new_file_name='=?utf-8?b?' + base64.b64encode(file_name.encode()).decode() + '?='
    #这里是处理文件名为中文名的,必须这么写
    att["Content-Disposition"] = 'attachment; filename="%s"'%(new_file_name)
    msg.attach(att)
    msg.attach(MIMEText(self.content))#邮件正文的内容
    msg['Subject'] = self.title # 邮件主题
    msg['From'] = self.username # 发送者账号
    msg['To'] = ','.join(self.recv) # 接收者账号列表
    if self.ssl:
    self.smtp = smtplib.SMTP_SSL(self.email_host,port=self.ssl_port)
    else:
    self.smtp = smtplib.SMTP(self.email_host,port=self.port)
    #发送邮件服务器的对象
    self.smtp.login(self.username, self.passwd)
    try:
    self.smtp.sendmail(self.username, self.recv, msg.as_string())
    pass
    except Exception as e:
    print('出错了。。',e)
    else:
    print('发送成功!')
    self.smtp.quit()


    if __name__ == '__main__':
    m = SendMail(
    username='842167869@qq.com',
    passwd='ukmzawnjhtkybfdc',
    recv=['842167869@qq.com', '842167869@qq.com'],
    title='新鞋的发送邮件',
    content='哈哈哈啊哈哈哈哈',
    file=r'C:UsersAdministratorDesktop测试用例.xlsx', ssl=True,
    )
    m.send_mail()

    #生成测试报告功能实现
    import time
    from conf.setting import REPORT_PATH

    class HtmlReport(object):
    __style_html = '''
    <style type="text/css">
    body {
    font:normal 68% verdana,arial,helvetica;
    color:#000000;
    }
    table tr td, table tr th {
    font-size: 68%;
    }
    table.details tr th{
    color: #ffffff;
    font-weight: bold;
    text-align:center;
    background:#2674a6;
    }
    table.details tr td{
    background:#eeeee0;
    }
    h1 {
    margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
    }
    h2 {
    margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
    }
    h3 {
    margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
    }
    .Failure {
    font-weight:bold; color:red;
    }


    img
    {
    border- 0px;
    }

    .expand_link
    {
    position=absolute;
    right: 0px;
    27px;
    top: 1px;
    height: 27px;
    }

    .page_details
    {
    display: none;
    }

    .page_details_expanded
    {
    display: block;
    display/* hide this definition from IE5/6 */: table-row;
    }


    </style>
    <script language="JavaScript">
    function show(details_id)
    {
    var close = 'page_details';
    var show = 'page_details_expanded';
    if (document.getElementById(details_id).className==close){
    document.getElementById(details_id).className = show;
    }
    else {
    document.getElementById(details_id).className = close;
    }

    }

    </script>
    '''
    __report_html = '''
    <!DOCTYPE html>
    <html>
    <head>
    <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>接口测试报告</title>
    {style}
    </head>
    <body>
    <h1>接口测试报告</h1>
    <table width="100%">
    <tr>
    <td align="left">测试时间: {date}</td>
    </tr>
    </table>
    <hr size="1">
    <h2>测试概况</h2>
    <table width="95%" cellspacing="2" cellpadding="5" border="0" class="details" align="center">
    <tr valign="top">
    <th>用例总数</th><th>通过数量</th><th>失败数量</th><th>运行时间</th>
    </tr>
    <tr valign="top" class="">
    <td align="center">{all}</td><td align="center">{ok}</td><td align="center">{fail}</td><td align="center">{run_time} s</td>
    </tr>
    </table>
    <hr align="center" width="95%" size="1">
    <h2>接口详细</h2>
    <table width="95%" cellspacing="2" cellpadding="5" border="0" class="details" align="center">
    <tr valign="top">
    <th>所属项目</th><th>模块</th><th>用例描述</th><th>URL</th><th>测试人员</th><th>用例状态</th><th></th>
    </tr>{case_res}</table>
    <hr align="center" width="95%" size="1">
    </body>
    </html>

    '''
    __case_html = '''
    <tr valign="top" class="">
    <td>{project}</td><td align="center">{model}</td><td align="center">{detail}</td><td align="center">{url}</td><td align="center">{tester}</td><td align="center">{status}</td><td align="center"><a href="#" onclick="show('page_details_{case_id}');">查看接口详细</a></td>
    </tr>
    <tr class="page_details" id="page_details_{case_id}">
    <td bgcolor="#FF0000" colspan="8">
    <div align="center">
    <b>请求/返回 "{project}"</b>
    <table width="95%" cellspacing="1" cellpadding="1" border="0" bgcolor="#2674A6" bordercolor="#000000">
    <tr>
    <th>请求报文</th><th>返回报文</th>
    </tr>
    <tr>
    <td align="center" style="width :300px;word-break: break-all;"><span>{request}</span></td><td align="center" style="width :300px;word-break: break-all;" ><span>{response}</span></td>

    </tr>
    </table>
    </div>
    </td>
    </tr>

    '''
    def __init__(self,report_dic):
    '''

    :param report_dic:生成报告需要用的字典
    {
    "all": 5,#运行用例数量
    "ok": 4,#通过数量
    "fail": 1,#失败数量
    "run_time": 100,#运行时间,单位s
    "case_res": [{}],#每条用例的执行结果,
    case_res:
    {
    "case_id":"001",#用例id
    "project":"搜索",#所属项目
    "model":"登录",#模块
    "detail":"正常登录",#用例标题
    "url":"http://10.165.124.28:8080/q", #请求url
    "tester":"问问", #测试人员
    "status":"通过",#测试结果
    "request":"a=1&b=2",#请求报文
    "response":"{'code':200,'msg':'操作成功'}"#返回报文
    }
    }
    '''

    self.report_dic = report_dic
    def report(self):
    res_list_html = ''
    res_list = self.report_dic.get('case_res')
    for res in res_list:
    res_list_html+=self.__case_html.format(**res)
    self.report_dic['case_res']=res_list_html
    self.report_dic['style'] = self.__style_html
    self.report_dic['date'] = time.strftime('%Y/%m/%d %H:%M:%S')
    self.__write_file()
    def __write_file(self):
    with open('{path}{date}_TestReport.html'.format(path = REPORT_PATH,date=time.strftime('%Y%m%d%H%M%S')),'w',encoding='utf-8') as fw:
    fw.write(self.__report_html.format(**self.report_dic))
    def ReportParh(self):
    report_path ='{path}{date}_TestReport.html'.format(path = REPORT_PATH,date=time.strftime('%Y%m%d%H%M%S'))
    return report_path

    #执行测试
    from lib.tools import readCase, my_request, check_res, urlParam, write_excel
    import time
    from lib.report import HtmlReport
    from lib.sendmail import SendMail

    def do_test():
    #执行接口测试结束后,生成excel,保存在data目录下
    case_list = readCase(r'D:UsersAdministratorPycharmProjectsall_viewMyFramecases测试用例.xlsx')
    result_list = []
    for case in case_list:
    # print(case)
    data = case[6]
    method = case[5]
    url = case[4]
    res =my_request(method, url, data) #请求后,返回的报文
    res = res.replace(' ', '')
    hope = case[7]
    test_result = check_res(res, hope)#测试结果,是否通过的
    request_msg = url + '?' + urlParam(data)#请求报文
    #把请求报文,返回报文,测试结果 ,组成一个列表
    result = [request_msg, res, test_result]
    result_list.append(result)
    testcase_path = r'D:UsersAdministratorPycharmProjectsall_viewMyFramecases测试用例.xlsx'
    path = write_excel(testcase_path, result_list)#写入到excel里面
    return path#获取要生成报告的excel
    # do_test()

    def MakeReport(end_case_path):
    case_list = readCase(end_case_path)
    print(case_list)
    count = 0
    case_ok = []
    res_list = []
    for Rcase in case_list:
    if Rcase[10]:#如果返回结果是真的,成功的,直接加载case_ok里面
    case_ok.append(Rcase[10])
    res = {
    "case_id":Rcase[2],
    "project":Rcase[0],
    "model":Rcase[1],
    "detail":Rcase[3],
    "url":Rcase[4],
    "tester":Rcase[11],
    "status":Rcase[10],
    "request":Rcase[6],
    "response":Rcase[9]
    }
    res_list.append(res)
    count+=1

    all = {

    "all": count,#总共多少条用例
    "ok": len(case_ok),#通过的
    "fail": count-len(case_ok),#失败
    "run_time": 100,#运行了多久
    "case_res": res_list,
    "date": time.strftime('%Y/%m/%d %H:%M:%S')#什么时候执行的

    }

    a = HtmlReport(all)
    a.report()
    a.ReportParh()
    report_path = a.ReportParh()
    return report_path
    # print('报告路径',file_name)

    def send_report(report_path):

    m = SendMail(
    username='xxxx@qq.com',
    passwd='xxxxx',
    recv=['xxx@qq.com','xxx@qq.com','xxx@qq.com'],
    title='自制框架测试报告发送,哇哈哈哈!阿飞~~',
    content='最新一次执行结果报告发送~',
    file=report_path, ssl=True,
    )
    m.send_mail()









     
  • 相关阅读:
    Android weight属性详解
    设计模式(一)__单例设计模式
    Java中线程的生命周期
    抽象类和接口
    SQL sever 怎样将DBF文件导入到数据库
    JS去除字符串中空格,及常用正则表达式
    Oracle 11g问题1:关于error:ORA12541: TNS: 没有监听器
    access、excel取随机n条记录
    tsql字符串操作
    测试SQL Server执行时间和CPU时间
  • 原文地址:https://www.cnblogs.com/wmm007/p/8066027.html
Copyright © 2020-2023  润新知