接口测试框架-[pytest+requests+excel]读取excel表格+requests参数化+pytest测试报告

用例示范

目录结构

1.demo

demo1.py

'''
pip install xlrd
pip install xlwt
'''
import xlrd
import json
import requests
from bs4 import BeautifulSoup

import xlrd

# row 是行
# col 是列

file_path = r'接口测试示例.xlsx'

# 拿到book对象 xlrd.open_workbook方法
book = xlrd.open_workbook(file_path)
print(book)

# 拿到表格中对象 按索引获取
sheet = book.sheet_by_index(0)
print(sheet)

# 按名字获取
sheet1 = book.sheet_by_name('接口自动化用例')
print(sheet1)

# 行,列 获取到所有的行和列 sheet.nrows方法, sheet.ncols方法
rows, cols = sheet.nrows, sheet.ncols
print(rows, cols)

# for循环出每一行
for row in range(rows):
    print(sheet.row_values(row))

# for循环出每一列
for col in range(cols):
    print(sheet.col_values(col))

# 按索引取出行列
print(sheet.row_values(2))

print(sheet.col_values(0))

print(sheet.cell(0, 0))

# 将行和列的值拼接在一起 组合成[{},{}]的样式 zip拉在一起 dict转一下
l = []
title = sheet.row_values(0)
for i in range(1, rows):
    l.append(dict(zip(title, sheet.row_values(i))))

print(l)


def get_excel_data():
    file_path = r'接口测试示例.xlsx'

    # 获取到book对象
    book = xlrd.open_workbook(file_path)
    # print(book)
    # 获取sheet对象
    sheet = book.sheet_by_index(0)
    # sheet = book.sheet_by_name('接口自动化用例')
    # sheets = book.sheets()  # 获取所有的sheet对象

    rows, cols = sheet.nrows, sheet.ncols
    l = []
    # print(sheet.row_values(0))
    title = sheet.row_values(0)
    # print(title)
    # 获取其他行
    for i in range(1, rows):
        # print(sheet.row_values(i))
        l.append(dict(zip(title, sheet.row_values(i))))

    return l
r = requests.get('https://www.cnblogs.com/Neeo/articles/11667962.html')
s = BeautifulSoup(r.text, 'html.parser')
print(s.find('title').text)

2.uti

ExcelHandler

'''

关于Excel表的操作
'''

import xlrd
from settings import conf


class ExcelHandler(object):

    @property
    def get_excel_data(self):
        # 获取到book对象
        book = xlrd.open_workbook(conf.TEST_CASE_PATH)
        # print(book)
        # 获取sheet对象
        sheet = book.sheet_by_index(0)
        # sheet = book.sheet_by_name('接口自动化用例')
        # sheets = book.sheets()  # 获取所有的sheet对象

        rows, cols = sheet.nrows, sheet.ncols
        l = []
        # print(sheet.row_values(0))
        title = sheet.row_values(0)
        # print(title)
        # 获取其他行
        for i in range(1, rows):
            # print(sheet.row_values(i))
            l.append(dict(zip(title, sheet.row_values(i))))
        return l

RequestsHandler.py


'''

请求相关
'''

import json
import requests
from bs4 import BeautifulSoup
from uti.LoggerHandler import logger


class RequestHandler(object):

    def __init__(self, case):
        self.case = case
        try:
            self.case_expect = json.loads(self.case['case_expect'])
        except:
            self.case_expect = self.case['case_expect']

    @property
    def get_response(self):
        """ 获取请求结果 """
        response = self.send_request()
        return response

    def send_request(self):
        """ 发请求 """
        try:
            response = requests.request(
                method=self.case['case_method'],
                url=self.case['case_url'],
                params=self._check_params()
            )
            content_type = response.headers['Content-Type']
            content_type = content_type.split(";")[0].split('/')[-1] if ';' in content_type else \
            content_type.split("/")[-1]
            if hasattr(self, '_check_{}_response'.format(content_type)):
                response = getattr(self, '_check_{}_response'.format(content_type))(response)
            else:
                raise '返回类型为: {}, 无法解析'.format(content_type)
        except:
            logger().error({'response': "请求发送失败,详细信息: url={}".format(self.case['case_url'])})
            return {'response': "请求发送失败,详细信息: url={}".format(self.case['case_url'])}, self.case['case_expect']

        return response

    def _check_json_response(self, response):
        """  处理json类型的返回值 """
        response = response.json()  # {'success': True}
        for key in self.case_expect:
            if self.case_expect[key] != response[key]:  # 用例执行失败的
                return {key: self.case_expect[key]}, {key: response[key]}
        else:  # 执行成功
            logger("发送请求").info('{} 执行成功'.format(self.case['case_url']))
            return {key: self.case_expect[key]}, {key: response[key]}

    def _check_html_response(self, response):
        """ 校验html类型的数据"""
        soup_obj = BeautifulSoup(response.text, 'html.parser')
        title = soup_obj.find('title').text
        return title, self.case_expect

    def _check_params(self):
        """ 整理参数 """
        if self.case['case_params']:
            """
            做扩展
            """
            pass
        else:
            return {}

AllureHandler

import subprocess
from settings import conf

class AllureHandler(object):

    def execute_command(self):
        import time
        time.sleep(1)
        subprocess.call(conf.ALLURE_COMMAND, shell=True)

EmailHandler


'''
发邮件
'''
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from settings import conf

from uti.LoggerHandler import logger


class EmailHandler(object):

    def read_report(self):
        f = open(conf.TEST_CASE_REPORT_PATH, 'rb')
        return f.read()

    def send_email(self):
        """ 发送邮件 """

        # 第三方 SMTP 服务
        mail_host = "smtp.qq.com"  # 设置服务器
        mail_user = "xxx@qq.com"  # 用户名
        mail_pass = "xxx"  # 口令
        # 获取口令地址 https://www.cnblogs.com/zhangshan33/p/11943755.html

        # 设置收件人和发件人
        sender = 'xxx@qq.com'
        receivers = ['xxx@qq.com', ]  # 接收邮件,可设置为你的QQ邮箱或者其他邮箱

        # 创建一个带附件的实例对象
        message = MIMEMultipart()

        # 邮件主题、收件人、发件人
        subject = '请查阅--测试报告'  # 邮件主题
        message['Subject'] = Header(subject, 'utf-8')
        message['From'] = Header("{}".format(sender), 'utf-8')  # 发件人
        message['To'] = Header("{}".format(';'.join(receivers)), 'utf-8')  # 收件人

        # 邮件正文内容 html 形式邮件
        send_content = self.read_report()  # 获取测试报告
        html = MIMEText(_text=send_content, _subtype='html', _charset='utf-8')  # 第一个参数为邮件内容

        # 构造附件
        att = MIMEText(_text=send_content, _subtype='base64', _charset='utf-8')
        att["Content-Type"] = 'application/octet-stream'
        file_name = 'report.html'
        att["Content-Disposition"] = 'attachment; filename="{}"'.format(file_name)  # # filename 为邮件附件中显示什么名字
        message.attach(html)
        message.attach(att)

        try:
            smtp_obj = smtplib.SMTP()
            smtp_obj.connect(mail_host, 25)  # 25 为 SMTP 端口号
            smtp_obj.login(mail_user, mail_pass)
            smtp_obj.sendmail(sender, receivers, message.as_string())
            smtp_obj.quit()
            logger().info("邮件发送成功")

        except smtplib.SMTPException:
            logger().error("Error: 无法发送邮件")

LoggerHandler

import logging
from settings import conf


class LoggerHandler:
    """ 日志操作 """
    _logger_level = {
        'debug': logging.DEBUG,
        'info': logging.INFO,
        'warning': logging.WARNING,
        'error': logging.ERROR,
        'critical': logging.CRITICAL
    }

    def __init__(self, log_name, file_name, logger_level, stream_level='info', file_level='warning'):
        self.log_name = log_name
        self.file_name = file_name
        self.logger_level = self._logger_level.get(logger_level, 'debug')
        self.stream_level = self._logger_level.get(stream_level, 'info')
        self.file_level = self._logger_level.get(file_level, 'warning')
        # 创建日志对象
        self.logger = logging.getLogger(self.log_name)
        # 设置日志级别
        self.logger.setLevel(self.logger_level)
        if not self.logger.handlers:
            # 设置日志输出流
            f_stream = logging.StreamHandler()
            f_file = logging.FileHandler(self.file_name)
            # 设置输出流级别
            f_stream.setLevel(self.stream_level)
            f_file.setLevel(self.file_level)
            # 设置日志输出格式
            formatter = logging.Formatter(
                "%(asctime)s %(name)s %(levelname)s %(message)s"
            )
            f_stream.setFormatter(formatter)
            f_file.setFormatter(formatter)
            self.logger.addHandler(f_stream)
            self.logger.addHandler(f_file)

    @property
    def get_logger(self):
        return self.logger


def logger(log_name='接口测试'):
    return LoggerHandler(
        log_name=log_name,
        logger_level=conf.LOG_LEVEL,
        file_name=conf.LOG_FILE_NAME,
        stream_level=conf.LOG_STREAM_LEVEL,
        file_level=conf.LOG_FILE_LEVEL
    ).get_logger


if __name__ == '__main__':
    logger().debug('aaaa')
    logger().info('aaaa')
    logger().warning('aaaa')

3.scripts

test_case

import pytest
import allure
from uti.ExcelHandler import ExcelHandler
from uti.RequestHandler import RequestHandler
from uti.AllureHandler import AllureHandler
from uti.EmailHandler import EmailHandler
'''
1. 拿到Excel数据
2. 发请求
3. 生成测试用例报告
4. 发邮件
5. 断言

'''


class Test_case(object):
    @pytest.mark.parametrize('case', ExcelHandler().get_excel_data)
    def test_case(self, case):
        """  执行断言 """
        # print(case)
        # 发请求
        response = RequestHandler(case).get_response

        # 制作 allure 报告
        allure.dynamic.title(case['case_project'])
        allure.dynamic.description('<font color="red">请求URL:</font>{}<br />'
                                   '<font color="red">期望值:</font>{}'.format(case['case_url'], case['case_description']))
        allure.dynamic.feature(case['case_project'])
        allure.dynamic.story(case['case_method'])
        assert response[0] == response[1]

    def teardown_class(self):
        """  执行alllure命令 """

        AllureHandler().execute_command()
        # 发邮件
        EmailHandler().send_email()

4.settings

conf.py


import os
import datetime

BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# 脚本路径
file_path = '接口测试示例.xlsx'
TEST_CASE_PATH = os.path.join(BASE_PATH, 'data', file_path)

# 报告路径
TEST_CASE_REPORT_PATH = os.path.join(BASE_PATH, 'report', 'report.html')

# CASE_METHOD = 'case_method'


# ------------ allure 相关配置 -----------

result_path = os.path.join(BASE_PATH, 'report', 'result')
allure_html_path = os.path.join(BASE_PATH, 'report', 'allure_html')
ALLURE_COMMAND = 'allure generate {} -o {} --clean'.format(result_path, allure_html_path)

# ---------------- 日志相关 --------------------
# 日志级别
LOG_LEVEL = 'debug'
LOG_STREAM_LEVEL = 'debug'  # 屏幕输出流
LOG_FILE_LEVEL = 'info'  # 文件输出流

# 日志文件命名

LOG_FILE_NAME = os.path.join(BASE_PATH, 'logs', datetime.datetime.now().strftime('%Y-%m-%d') + '.log')

if __name__ == '__main__':
    print(TEST_CASE_PATH)

5.pytest.ini

[pytest]
addopts = -s -v --html=report/report.html --alluredir ./report/result
testpaths = ./scripts
python_files = test_*.py
python_classes = Test*
python_functions = test_*

6.run.py

import pytest

if __name__ == '__main__':
    pytest.main()

7.直接右击运行run.py文件


8.终端运行allure

allure generate report/result -o report/allure_html --clean

生成的测试报告

用浏览器打开

要发送的报告

用浏览器打开

9.邮箱收到的文件


GitHub代码

https://github.com/zhangshan33/ATScripts

posted @ 2019-11-27 10:36  张珊33  阅读(5896)  评论(3编辑  收藏  举报