登录
转载

python+unittest+requests接口自动化实战

发布于 2021-04-12 阅读 218
  • 后端
  • Python
转载

文章目录

    • 1.项目整体架构
    • 2.config.ini文件
    • 3.readConfig.py文件
    • 4.api层
    • 5.case层
    • 6.tools层
    • 7.data层
    • 8.log层
    • 9.report层
    • 10.run_suite.py文件
    • 11.发送邮件

1.项目整体架构

api:接口层 case:业务层 data:数据层 log:日志 report:报告 tools:工具层 config.ini:配置文件 readConfig.py:读取配置文件方法 run_suite.py:整体运行用例入口 send_email.py:发送邮件 图1

2.config.ini文件

说明:该文件为配置文件,用来存放一些不怎么改变的东西,例如:ip地址、数据库参数、接口地址、发送邮件人等等 创建config.ini文件,右键点击项目->选择New->点击File 图1 填写config.ini,点击ok 图片2 例如一个接口是这样的,我们假设它为登录接口: https://www.tokenin.cn/api/v2/report/hotMarkList 那我们可以把他拆分开,前面的是ip地址,后面的是项目文件地址,因为所有这个项目的接口前面的ip地址肯定是一样的,只是后面的项目文件地址不同罢了,我们分开的话,如果需要更换测试环境,只需要更改前面的ip地址就可以了 图3

注意:在这个配置文件里千万不要写备注,如果写了就会报错!

3.readConfig.py文件

作用:读取配置文件(config.ini) 创建常规的python文件就可以了,这个就不需要我教了吧。。。 图3 代码附上

import configparser
import os

"""
    读取配置文件
"""

# 创建对象
read_ini = configparser.ConfigParser()
# 获取当前文件路径
current_file_path = os.path.dirname(os.path.abspath(__file__))
# 读取配置文件内容
read_ini.read(current_file_path + "/config.ini")


# 接口拼接
def url_join(api):
    url = "http://" + get_host() + api
    return url


# IP地址
def get_host():
    return read_ini['API']['host']


# 登录接口
def get_hotMarkList():
    return url_join(read_ini['API']['hotMarkList'])


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


看到没,拼接出来了吧,一模一样,这样设计的话维护会省事很多!还不点个赞! 那么如何在api层case层进行调用呢,别着急,慢慢往下看

4.api层

作用:该地址的请求方式,返回结果 文件格式:api_接口名称 图4

get请求方式:不需要token等其他信息

import requests
from readConfig import *


# 登录接口
class ApiHotMarkList(object):
    def api_hot_mark_list(self, username, password):
        params = {"username": username, "password": password}
        return requests.get(get_hotMarkList(), params=params)


if __name__ == '__main__':
    api = ApiHotMarkList()
    a = api.api_hot_mark_list("登录账号", "密码")
    print(a.json())


git请求方式:需要token等其他信息(具体需要什么去问开发人员,他比你清楚,或者你也可以使用postman请求成功后,把Headers里面的隐藏内容整出来加到headers里,然后一个一个去除,看看到底需要哪个)

import requests
from readConfig import *


# 登录接口
class ApiHotMarkList(object):
    def api_hot_mark_list(self, username, password, token, cookie):
        params = {"username": username, "password": password}
        headers = {"Authorization": token, "Cookie": cookie}
        return requests.get(get_hotMarkList(), headers=headers, params=params)


if __name__ == '__main__':
    api = ApiHotMarkList()
    a = api.api_hot_mark_list("登录账号", "密码", "token值", "cookie值")
    print(a.json())


post请求:

import requests
from readConfig import *


# 登录接口
class ApiHotMarkList(object):
    def api_hot_mark_list(self, username, password, token, cookie):
        data = {"username": username, "password": password}
        headers = {"Authorization": token, "Cookie": cookie}
        return requests.post(get_hotMarkList(), headers=headers, data=data)


if __name__ == '__main__':
    api = ApiHotMarkList()
    a = api.api_hot_mark_list("登录账号", "密码", "token值", "cookie值")
    print(a.json())


下面再讲个小技巧,比如有这么个业务需求:登录->获取用户列表信息 那么这个获取用户列表信息接口肯定需要登录成功后才能请求,那么我们就需要一个登录成功接口,如何进行呢?请继续往下看。 首先在config.ini文件里面填写登录成功的账号密码,如下: 图5 然后在readConfig.py文件里面写获取成功登录账号密码的方法,如下: 图6 然后在api层的登录接口类文件里写成功登录接口方法

import requests
from readConfig import *


# 登录接口类
class ApiHotMarkList(object):
    # 登录接口
    def api_hot_mark_list(self, username, password):
        data = {"username": username, "password": password}
        return requests.post(get_hotMarkList(), data=data)

    # 成功登录接口方法
    def api__hot_mark_list_success(self, username, password):
        data = {"username": username, "password": password}
        login_value = requests.post(get_hotMarkList(), headers=headers, data=data)
        # 获取cookie
        cookie_dic = requests.utils.dict_from_cookiejar(login_value.cookies)
        cookie = self.get_cookie(cookie_dic)
        return login_value, cookie

    # cookie遍历方法
    def get_cookie(self, cookie_dic):
        for key in cookie_dic.keys():
            for value in cookie_dic.values():
                return key + "=" + value


if __name__ == '__main__':
    api = ApiHotMarkList()
    a = api.api_hot_mark_list("登录账号", "密码")
    print(a.json())


然后在case调用就ok啦

5.case层

作用:业务方法层,也可以理解为用例层 文件名:必须以test开头,后面加上数字,然后加上用例名称

import unittest
from parameterized import parameterized
from readConfig import *
from api.api_hot_mark_list import *
from tool.get_logger import GetLogger
from tool.read_json import read_json

log = GetLogger.get_logger()


class TestLogin(unittest.TestCase):
    @parameterized.expand(read_json("login.json"))
    def test_login(self, username, password, status_code, expect):
        # 调用成功登录方法
        login_success = ApiHotMarkList().api__hot_mark_list_success(get_username(), get_password())
        log.info("成功登录接口,返回信息为:{}".format(login_success.json()))
        # 断言状态码
        self.assertEqual(status_code, login_success.json()['status'])
        # 断言响应信息
        self.assertEqual(expect, login_success.json()['message'])

        # 调用登录方法
        login = ApiHotMarkList().api_hot_mark_list(username, password)
        log.info("登录接口,返回信息为:{}".format(login.json()))
        # 断言状态码
        self.assertEqual(status_code, login.json()['status'])
        # 断言响应信息
        self.assertEqual(expect, login.json()['message'])


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



6.tools层

下面我截图的时候写错了,应该是tools,因为工具有很多嘛 作用:提供一些工具方法,如:读取json、读取报告、日志等等 图7 日志:get_logger.py

import logging.handlers
import os
import time


class GetLogger:
    __logger = None

    @classmethod
    def get_logger(cls):
        if cls.__logger is None:
            # 获取日志器
            cls.__logger = logging.getLogger()
            # 设置日志器级别
            cls.__logger.setLevel(logging.INFO)
            # 当前文件路径
            current_file_path = os.path.dirname(os.path.abspath(__file__))
            # 当前文件所在文件夹路径
            current_file_dir_path = os.path.dirname(current_file_path)
            file = current_file_dir_path + os.sep + "log" + os.sep + "{}.log".format(time.strftime("%Y-%m-%d"))
            # 获取处理器 文件-以时间分割
            """
            filename:文件路径及文件名
            maxBytes:最大字节,1024 * 1024为1M,达到200M压缩
            backupCount:备份的日志数量(备份7个,多余的删除)
            encoding:编码格式
            """
            th = logging.handlers.RotatingFileHandler(filename=file,
                                                      maxBytes=1024 * 1024 * 200,
                                                      backupCount=7,
                                                      encoding="utf-8")

            # 设置格式器
            fmt = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s [%(funcName)s:%(lineno)d] - %(message)s"
            fm = logging.Formatter(fmt)

            # 将格式器添加到处理器 文件
            th.setFormatter(fm)
            # 将处理器添加到日志器
            cls.__logger.addHandler(th)
        return cls.__logger


if __name__ == '__main__':
    log = GetLogger.get_logger()
    for i in range(1000):
        log.info("测试打印日志")


读取报告:read_html.py

import os
import re
import time


# 读取报告html数据
def read_html():
    # 当前文件路径
    current_file_path = os.path.dirname(os.path.abspath(__file__))
    # 当前文件所在文件夹路径
    current_file_dir_path = os.path.dirname(current_file_path)
    file_path = current_file_dir_path + "/report/" + '{}.html'.format(time.strftime("%Y-%m-%d"))
    with open(file_path, 'r', encoding='utf-8') as f:
        error_log = f.read()  # 读取html网页
        pattren = re.compile(
            "<tr id='total_row'>.*?<td>Total</td>.*?<td>(.*?)</td>.*?<td>(.*?)</td>.*?<td>(.*?)</td>.*?<td>(.*?)</td>.*?<td>&nbsp;</td>",
            re.S)  # 正则表达式
        r_list = pattren.findall(error_log)  # 正则匹配文件内容
        return r_list


if __name__ == '__main__':
    print(read_html()[0][0])


读取json文件:read_json.py

import json
import os


# 读取json数据
def read_json(filename):
    # 定义空列表 组装测试数据
    arr = []
    # 当前文件路径
    current_file_path = os.path.dirname(os.path.abspath(__file__))
    # 当前文件所在文件夹路径
    current_file_dir_path = os.path.dirname(current_file_path)
    file_path = current_file_dir_path + "/data/" + filename
    # 打开json文件并获取文件流
    with open(file_path, "r", encoding="utf-8")as f:
        # 遍历 调用yaml.safe_load(f).values()方法
        for datas in json.load(f).values():
            arr.append(tuple(datas.values()))
        # 返回 结果
        return arr


if __name__ == '__main__':
    print(read_json("login.json"))


7.data层

作用:以json格式存放数据(也可以根据自己喜好用其他格式文件存放数据) 图8

8.log层

作用:存放日志 图9

9.report层

作用:存放报告 图10 图11

10.run_suite.py文件

作用:整个程序运行入口

import unittest
import time
from tools.HTMLTestRunner import HTMLTestRunner

"""
    用例整体运行入口
"""

# 组装测试套件
suite = unittest.defaultTestLoader.discover("./case", pattern="test*.py")
# 指定报告存放路径及文件名称
file_path = "./report/{}.html".format(time.strftime("%Y-%m-%d"))
# 运行测试套件并生成测试报告
with open(file_path, "wb")as f:
    HTMLTestRunner(stream=f, title="自定义报告标题").run(suite)


11.发送邮件

作用:发送邮件

import smtplib
from email.mime.text import MIMEText
from email.header import Header
import time
from datetime import date
from readConfig import *
from tools.get_logger import GetLogger
from tools.read_html import read_html

log = GetLogger.get_logger()
date = date.today()


# 发送邮件
def send_mail(body):
    try:
        # 邮件正文是MIMEText
        msg = MIMEText(body, 'html', 'utf-8')
        # 邮件对象
        msg['Subject'] = Header("发送邮件的标题".format(date), 'utf-8').encode()  # 标题
        msg['From'] = Header(u'{} <{}>'.format('发件人邮箱,例如:xiaoming@qq.com', sender))  # 发件人
        msg['To'] = Header(u'收件人 <%s>' % recipient)  # 发送的用户
        msg['date'] = time.strftime("%a,%d %b %Y %H:%M:%S %z")  # 发送时间日期
        # 发送邮件
        smtp = smtplib.SMTP()
        smtp.connect('smtp.exmail.qq.com', 25)  # 邮箱服务器,需查看服务器是否开启25端口
        smtp.login(username, password)  # 登录邮箱
        smtp.sendmail(sender, recipient.split(','), msg.as_string())  # 发送者和接收者
        smtp.quit()
        log.info("邮件已发出,注意查收!")
    except Exception as e:
        log.error("邮件发送失败!".format(e))


# 发件箱用户名
username = get_email_username()
# 发件箱密码
password = get_email_password()
# 发件人邮箱
sender = get_email_sender()
# 收件人邮箱
recipient = get_email_recipient()
# 报告地址
report = get_email_report_url().format(date)
body = """
        <p>本次接口自动化执行的测试环境为:{}</p>
        <p>总共执行用例{}条,其中pass={}条,fail={}条,error={}条。</p>
        <p>详情请查看报告:{}</p>
        """.format(get_host(), read_html()[0][0], read_html()[0][1], read_html()[0][2], read_html()[0][3], report)
send_mail(body)


get_email_username()、get_email_password()、get_email_sender()、get_email_recipient()、get_email_report_url()都是调用的readConfig文件里的方法从config.ini文件里获取的,上面有详细介绍。

这次就分享到这里吧,有问题联系我就好,写这篇文章一是总结,二是希望能给迷茫的你一种思路,谢谢大家!

评论区

励志做一条安静的咸鱼,从此走上人生巅峰。

0

0

0

举报