python 接口自动化实战

项目框架:

安装pytest: pip install pytest

安装pytest-html :pip install pytest-html

安装pytest-allure :pip install pytest-allure

安装pytest-rerunfailures :pip install  pytest-rerunfailures (执行失败后继续执行指定的次数  --reruns 2)

下载allure: https://www.cnblogs.com/desireyang/p/12517269.html

注意:用例保存为Microsoft excel   切勿保存为wps加密的,python读取时可能会报错

执行方式:pytest

send_request.py

import requests
import json

from utils.log_handle import logger


class SendRequest(object):
    def __init__(self, case):

        self.method = case["method"] if case else None
        self.url = case["url"] if case else None
        self.description = case["description"] if case["description"] else None
        self.param = json.loads(case["param"], strict=False) if case["param"] else None
        self.headers = json.loads(case["headers"], strict=False) if case["headers"] else None
        self.data = json.loads(case["data"], strict=False) if case["data"] else None
        self.except_result = json.loads(case["except_result"], strict=False) if case["except_result"] else None
        self.Pass = True
        self.row = case["number"] if case["number"] else None

    # 处理是get还是post请求
    def request_handle(self):
        if self.method == "get":
            return self.get_request()

        else:
            self.post_request()

    # 发送get请求
    def get_request(self):
        rep = requests.get(url=self.url, headers=self.headers, params=self.param)
        real_resutl = rep.json()
        return self.assert_result(real_resutl)

    # 发送post
    def post_request(self):
        rep = requests.post(url=self.url, headers=self.headers, data=self.param, )
        real_result = rep.json()
        return self.assert_result(real_result)

    # 断言返回结果
    def assert_result(self, real_result):

        try:

            assert real_result == self.except_result
            logger().info("%s 断言成功" % self.description)

        except:
            self.Pass = False
            logger().info("%s 断言失败,预计结果:%s,实际结果:%s" % (self.description,self.except_result,real_result))
            raise AssertionError

        finally:
            from cases.bai_api import execel
            # 将真实结果写入execel
            execel.writeexecel(self.row, 9, str(real_result))

            # 是否通过
            execel.writeexecel(self.row, 10, self.Pass)
            execel.saveexecel()
            return real_result, self.Pass

 

 

 bai_api.py

import json
import os

import pytest

from api.send_request import SendRequest
from config import caseexecel_name, ALLURE_COMMAND
from utils.email_handle import EmailHandler
from utils.excel_handle import ExecelHandle
from utils.log_handle import logger

execel = ExecelHandle(caseexecel_name)


class TestBaiDu():

    @pytest.mark.parametrize("case", execel.readexecel())
    def test_baidu(self, case):
        logger().info("开始执行用例%s" % case["number"])
        # 执行api 请求
        SendRequest(case).request_handle()
        # 生成allure报告
        try:
            # popen可以执行cmd命令
            os.popen(ALLURE_COMMAND)
            logger().warning("allure报告生成成功")
        except:

            logger().warning("输入报告错误")
            #发送邮件
        try:
            EmailHandler().send_email()
            logger().warning("邮件报告生成功")
        except:
            logger().warning("邮件报告生成失败")


if __name__ == '__main__':
    pytest.main(["-s", "./bai_api.py"])

 students.xls 

注意:这里建议保存为Microsoft excel   切勿保存为wps加密的,会报错

 

 生成的日志:

 

 生成的allure 报告:

生成的pytest-html 报告:

 将测试结果填入表格:


email_handle.py

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formataddr

from config import PYTEST_HTML_PATH
from utils.log_handle import logger


class EmailHandler():
    def __init__(self):
        self.my_sender = 'kx113578@163.com'  # 发件人邮箱账号
        self.my_pass = '##########'  # 发件人邮箱密码,此处为授权码
        self.my_user = '1135790024@qq.com'  # 收件人邮箱账号,我这边发送给自己

    def email_content(self):
        with open(PYTEST_HTML_PATH, "rb") as f:
            return f.read()

    def send_email(self):
        f = self.email_content()
        ret = True
        try:
            # 创建一个带附件的实例
            message = MIMEMultipart()
            msg = MIMEText('这是接口测试结果……', 'plain', 'utf-8')  # 这里面写的是发送的是html
            message['From'] = formataddr(["ke1", self.my_sender])  # 括号里的对应发件人邮箱昵称、发件人邮箱账号
            message['To'] = formataddr(["ke2", self.my_user])  # 括号里的对应收件人邮箱昵称、收件人邮箱账号
            message['Subject'] = "美丽商城接口测试"  # 邮件的主题,也可以说是标题
            message.attach(msg)  # 邮件正文内容
            # 添加附件
            att1 = MIMEText(f, 'html', 'utf-8')
            att1["Content-Type"] = 'application/octet-stream'
            # 这里的filename可以任意写,写什么名字,邮件中显示什么名字
            att1["Content-Disposition"] = 'attachment; filename="report.html"'
            message.attach(att1)
            # 发送邮件
            server = smtplib.SMTP_SSL("smtp.163.com", 465)  # 发件人邮箱中的SMTP服务器,端口是25
            server.login(self.my_sender, self.my_pass)  # 括号中对应的是发件人邮箱账号、邮箱密码
            server.sendmail(self.my_sender, [self.my_user, ], message.as_string())  # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
            server.quit()  # 关闭连接
        except Exception:  # 如果 try 中的语句没有执行,则会执行下面的 ret=False
            ret = False
            logger().info("邮件发送失败")
        logger().info("邮件发送成功")

        return ret
if __name__ == '__main__':
    EmailHandler().send_email()

execel_handle.py
 

import xlrd
from xlutils.copy import copy

from config import caseexecel_name, result_execel


class ExecelHandle():

    # 读取excel用例
    def __init__(self,name,sheet="Sheet1"):
        self.name = name
        self.rb = xlrd.open_workbook(self.name)
        # 不能多次copy,否则只保存一次结果
        self.wb = copy(self.rb)
        self.ws = self.wb.get_sheet(0)

        self.sheet=sheet

    def readexecel(self):
        self.rb = xlrd.open_workbook(self.name)
        rt = self.rb.sheet_by_name(self.sheet)
        self.list1=[]
        for row in range(0,rt.nrows):
            if row != 0:
                self.list1.append(dict(zip(rt.row_values(0),rt.row_values(row))))
        return self.list1

    def writeexecel(self,row,col,content):

        self.ws.write(row,col,content)
    def saveexecel(self):
        self.wb.save(result_execel)


if __name__ == '__main__':
    ExecelHandle(caseexecel_name).readexecel()

 log_handle.py

import logging
import config


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, encoding="utf-8")
            # 设置输出流级别
            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=config.LOG_LEVEL,
        file_name=config.LOG_FILE_NAME,
        stream_level=config.LOG_STREAM_LEVEL,
        file_level=config.LOG_FILE_LEVEL
    ).get_logger


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

 config.py

import os
import datetime
BASENAEM= os.path.dirname(os.path.abspath(__file__))
caseexecel_name = os.path.join(BASENAEM,"data","students.xls")
result_execel = os.path.join(BASENAEM,"results","students_result.xls")

result_path = os.path.join(BASENAEM, 'reports', 'result')
# ------------ allure 相关配置 -----------
allure_html_path = os.path.join(BASENAEM, 'reports', 'allure_html')
ALLURE_COMMAND = 'allure generate {} -o {} --clean'.format(result_path, allure_html_path)
#pytest-html 生成的报告
PYTEST_HTML_PATH = allure_html_path = os.path.join(BASENAEM, 'reports', 'report1.html')


#日志配置
LOG_LEVEL = 'debug'
LOG_STREAM_LEVEL = 'debug'  # 屏幕输出流
LOG_FILE_LEVEL = 'info'  # 文件输出流
# 日志文件命名
LOG_FILE_NAME = os.path.join(BASENAEM, 'log', datetime.datetime.now().strftime('%Y-%m-%d') + '.log')

pytest.ini

[pytest]
addopts = -s --html ./reports/report1.html  --alluredir ./reports/result  --reruns 2
test_paths = ./cases
python_classes = Test*
python_files = bai*.py
python_functions = test*
 

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值