• python--接口自动化


    日志文件

    import logging
    from logging import handlers
    from conf.setting import LOG_PATH


    class Logger(object):
    # 日志级别关系映射
    level_relations = {
    'debug': logging.DEBUG,
    'info': logging.INFO,
    'warning': logging.WARNING,
    'error': logging.ERROR,
    'crit': logging.CRITICAL
    }

    def __init__(self, filename, level='info', when='D', back_count=3,
    fmt='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
    self.logger = logging.getLogger(filename)
    self.logger.setLevel(self.level_relations.get(level)) # 设置日志级别
    format_str = logging.Formatter(fmt)
    sh = logging.StreamHandler()
    sh.setFormatter(format_str)
    th = handlers.TimedRotatingFileHandler(filename=filename, when=when,
    backupCount=back_count, encoding='utf-8')
    th.setFormatter(format_str)
    self.logger.addHandler(sh)
    self.logger.addHandler(th)


    log = Logger(LOG_PATH, level='debug').logger # 直接在本文件实例化,以后导入log就行,不需要实例化了

    if __name__ == '__main__':
    log = Logger('nhy.log')
    log.logger.debug('i的是100')
    log.logger.info('开机')
    log.logger.warning('警告 飞机没油了')
    log.logger.error('错误 飞机要爆炸')


    报告文件
    import time
    from conf.setting import REPORT_PATH
    import os


    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):
    self.file_name = os.path.join(REPORT_PATH, '{date}_TestReport.html'.format(date=time.strftime('%Y%m%d%H%M%S')))
    with open(self.file_name, 'w', encoding='utf-8') as fw:
    fw.write(self.__report_html.format(**self.report_dic))


    if __name__ == '__main__':
    res_list = [
    {
    "case_id": "1",
    "project": "易品",
    "model": "登录",
    "detail": "正常登录",
    "url": "http://10.165.124.28:8080/q",
    "tester": "牛牛",
    "status": "通过",
    "request": "a=1&b=2",
    "response": "{'code':200,'msg':'操作成功'}"
    }
    ]

    all = {
    "all": 5,
    "ok": 4,
    "fail": 1,
    "run_time": 100,
    "case_res": res_list,
    "date": time.strftime('%Y/%m/%d %H:%M:%S')
    }

    a = HtmlReport(all)
    a.report()



    发送邮件文件
    import smtplib
    import os
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    import base64


    # qq授权码
    # lfuhiziuplykbgdd
    # vavqwyhdvjdzcabh
    class SendMail(object):
    def __init__(self, username, passwd, recv, title, content,
    file=None, ssl=False,
    email_host='smtp.126.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 # 安全链接端口
    # self.smtp = smtp

    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('附件打不开!', e)
    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='389688559@qq.com',
    passwd='lfuhiziuplykbgdd',
    recv=['wangsilei@126.com', '511402865@qq.com'],
    title='过年好',
    content='新年快乐',
    file=r'C:UsersWangDesktop新年快乐.txt',
    ssl=True,
    )
    m.send_mail()



    工具文件,含多种方法
    import xlrd
    import os
    from common.MyLog import log
    import requests
    from xlutils.copy import copy
    import time
    from common.发送邮件最终版 import SendMail
    from conf.setting import MAIL_USER_INFO, MAIL_PASSWORD, RECV


    def read_case(case_path): # 读用例
    if os.path.isfile(case_path):
    book = xlrd.open_workbook(case_path)
    sheet = book.sheet_by_index(0)
    all_case = [] # 所有的测试用例
    for row in range(1, sheet.nrows):
    all_case.append(sheet.row_values(row)[:8])
    log.debug('用例信息为:%s' % all_case)
    log.info('总共读取了%s条测试用例' % len(all_case))

    return all_case
    else:
    log.error('读取用例不存在,用例路径为%s' % case_path)
    raise Exception('用例不存在!')


    class MyRequest(object): # 调接口
    @classmethod
    def post(cls, url, data):
    data = cls.str_to_dict(data)
    try:
    res = requests.post(url, data=data).text
    except Exception as e:
    log.error('接口调用出错,错误信息为%s,url为%s' % (e, url))
    res = e
    return res, data

    @classmethod
    def get(cls, url, data):
    data = cls.str_to_dict(data)
    try:
    res = requests.get(url, data=data).text
    except Exception as e:
    log.error('接口调用出错,错误信息为%s,url为%s' % (e, url))
    res = e
    return res, data

    @classmethod
    def str_to_dict(cls, st: str):
    # a=1&b=2&c=3
    # 1. &分割 ['a=1', 'b=2', 'c=3']
    # 2. ['a', '1']
    res = {}
    if st.strip():
    for d in st.split('&'):
    j = d.split('=')
    res[j[0]] = j[1]
    return res


    def check_res(expected, res): # 校验结果
    # error_code=0,userId=1
    """
    {
    "error_code": 0,
    "login_info": {
    "login_time": "20180311155222",
    "sign": "4beba93fceae97c997f40fd424696691",
    "userId": 1
    }
    }
    """
    new_res = res.replace('": "', '=').replace('": ', '=')
    for c in expected.split(','):
    # ['error_code=0', 'userId=1']
    if c not in new_res:
    return '失败'
    return '通过'


    def write_excel(case_path, all_res): # 结果写回excel
    # all_res存放所有的测试结果
    book1 = xlrd.open_workbook(case_path)
    book2 = copy(book1) # 拷贝一份原来的
    sheet = book2.get_sheet(0) # 获取第几个sheet页
    line = 1 # 行号
    for res in all_res:
    sheet.write(line, 8, str(res[0]))
    sheet.write(line, 9, res[1])
    sheet.write(line, 10, res[2])
    sheet.write(line, 11, res[3])
    line += 1
    book2.save(case_path)


    # all_res = [
    # ['{"usrname":"niuhanyang"}', '{xxxx}', '通过', '原宝青'],
    # ['{"usrname":"niuhanyang"}', '{xxxx}', '通过', '原宝青'],
    # ['{"usrname":"niuhanyang"}', '{xxxx}', '通过', '原宝青']
    #
    # ]
    # write_excel(r'C:UserswangsileiDesktop测试用例.xls', all_res)


    def send_report(all_count, pass_count, report_file=None): # 发送测试报告
    if report_file:
    title = time.strftime('%Y-%m-%d %H:%M:%S') + '接口测试报告'
    content = '''
    大家好!
    本次接口测试,共运行{all}条测试用例
    通过{ok}条
    失败{fail}条
    测试报告详细信息见附件!
    '''.format(all=all_count, ok=pass_count, fail=(all_count - pass_count))
    m = SendMail(MAIL_USER_INFO, MAIL_PASSWORD, RECV, title, content, file=report_file)
    m.send_mail()



    run文件
    import os
    import sys
    import time

    from common import tools
    from conf.setting import CASE_PATH, TESTER
    from common.tools import MyRequest
    from common.report import HtmlReport

    BASE_PATH = os.path.dirname(
    os.path.dirname(
    os.path.abspath(__file__)
    )
    )
    sys.path.insert(0, BASE_PATH)


    class RunCase(object):
    def find_case(self):
    for case_file in os.listdir(CASE_PATH):
    if case_file.endswith('.xls'):
    # 获取用例
    self.case_path = os.path.join(CASE_PATH, case_file)
    all_case = tools.read_case(self.case_path)
    self.run_case(all_case)

    def run_case(self, all_case):
    excel_res = [] # 写入excel的结果使用的
    report_res = {} # 给生成的函数使用的
    case_res = [] # 存放每个用例的结果
    pass_count = 0 # 通过的次数
    for case in all_case:
    project = case[0]
    model = case[1]
    case_id = case[2]
    case_detail = case[3]
    url = case[4]
    method = case[5]
    req_data = case[6]
    check = case[7]
    if method.upper() == 'POST':
    response, data = MyRequest.post(url, req_data)
    else:
    response, data = MyRequest.get(url, req_data)
    case_status = tools.check_res(check, response) # 获取用例执行结果
    pass_count = pass_count + 1 if case_status == '通过' else pass_count
    tmp_case_res = self.create_report(case_id, project, model, case_detail, url, TESTER, case_status, data, response)
    case_res.append(tmp_case_res)
    excel_res.append([data, response, case_status, TESTER]) # 把每条用例的结果加入到写excel的那个里面
    tools.write_excel(self.case_path, excel_res)
    all_cases_num = len(all_case)
    report_res['all'] = all_cases_num # 总共的用例数
    report_res['ok'] = pass_count # 通过的数量
    report_res['fail'] = all_cases_num - pass_count # 失败的数量
    report_res['case_res'] = case_res # 每条用例的结果
    report_res['date'] = time.strftime('%Y-%m-%d %H:%M:%S')
    report_res['run_time'] = 1
    report_obj = HtmlReport(report_res) # 实例化对象
    report_obj.report() # 生成报告
    tools.send_report(all_cases_num, pass_count, report_obj.file_name) # 发送测试报告
    print('测试运行完成。。。')

    def create_report(self, case_id, project, model, detail, url, tester, status, request, response):
    return {
    'case_id': case_id,
    'project': project,
    'model': model,
    'detail': detail,
    'url': url,
    'tester': tester,
    'status': status,
    'request': request,
    'response': response,
    }

    run = RunCase()
    run.find_case()



    配置文件
    import os

    BASE_PATH = os.path.dirname(
    os.path.dirname(
    os.path.abspath(__file__)
    )
    )
    LOG_PATH = os.path.join(BASE_PATH, 'logs', 'atp.log') # 日志路径
    REPORT_PATH = os.path.join(BASE_PATH, 'report') # 报告路径
    CASE_PATH = os.path.join(BASE_PATH, 'cases') # 用例的路径
    MAIL_USER_INFO = 'wangsilei@126.com'
    MAIL_PASSWORD = 'xxxxxxxx'
    RECV = ['389688559@qq.com', '356367764@qq.com']
    TESTER = '王思磊'
  • 相关阅读:
    MVC动态添加文本框,后台使用FormCollection接收
    使用结构struct作为Dictionary<TKey,TValue>的键
    扩展方法的几个实例,扩展基本类型、接口、通过反射让扩展方法使用私有成员等
    使用Enum.TryParse()实现枚举的安全转换
    .NET泛型04,使用Lazy<T>实现延迟加载
    .NET泛型03,泛型类型的转换,协变和逆变
    .NET泛型02,泛型的使用
    dd、split、csplit命令
    seq命令
    uniq命令
  • 原文地址:https://www.cnblogs.com/wangsilei/p/8572143.html
Copyright © 2020-2023  润新知