zoukankan      html  css  js  c++  java
  • 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 = '王思磊'
  • 相关阅读:
    POJ 1251 Jungle Roads
    1111 Online Map (30 分)
    1122 Hamiltonian Cycle (25 分)
    POJ 2560 Freckles
    1087 All Roads Lead to Rome (30 分)
    1072 Gas Station (30 分)
    1018 Public Bike Management (30 分)
    1030 Travel Plan (30 分)
    22. bootstrap组件#巨幕和旋转图标
    3. Spring配置文件
  • 原文地址:https://www.cnblogs.com/wangsilei/p/8572143.html
Copyright © 2011-2022 走看看