Python+Requests+Pytest 接口自动化测试脚本总结

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# fileName: run_method.py
import requests
 
 
class RunMethod(object):
 
    def post_main(self, url, headers, data):
        # 忽略不安全的请求警告信息
        requests.packages.urllib3.disable_warnings()
        # 遇到requests的ssl验证,若想直接跳过不验证,设置verify=False即可
        response = requests.post(url=url, headers=headers, data=data, verify=False)
        return response
 
    def get_main(self, url, headers, data=None):
        # 忽略不安全的请求警告信息
        requests.packages.urllib3.disable_warnings()
        response = requests.get(url=url, headers=headers, data=data, verify=False)
        return response
 
    def run_main(self, method, url, headers, data=None):
        # 忽略不安全的请求警告信息
        requests.packages.urllib3.disable_warnings()
        requests.adapters.DEFAULT_RETRIES = 5
 
        if method == "Post":
            res = self.post_main(url, headers, data)
        elif method == "Get":
            res = self.get_main(url, headers, data)
        # 将响应的的数据以字典数据结构和json数据格式返回
        return res.json()

2. 存储接口信息

使用yml文件作为配置文件,存储每一个接口信息,主要包括”接口名称、method、url、data和headers“,以及预期结果”expected“

# fileName: api_config.yml
 
host: https://XXX.com
 
login:
  name: 【登录】手机号码登录
  method: Post
  url: /v1/login/
  data:
    phone_country: 86
    phone_number: 1210000000
    password: 123456
    device_id: XXX
    device_name: Iphone8plus
    device_pubkey: XXX
  headers:
    Content-Type: application/x-www-form-urlencoded
    Authorization: Basic XXX
 
asset_main:
  name: 【资产】用户资产列表页
  method: Get
  url: /v2/main/
  headers:
    Authorization: Bearer
    app-version: 4.8.0
    device-id: XXX
  expected:
    success: true
 
lend:
  name: 发送请求
  method: Post
  url: /v1/lend/
  data:
    payment_password: 123456
    amount: 100
    pledge_source: 1
  headers:
    Content-Type: application/x-www-form-urlencoded
    Authorization: Bearer
    device-id: XXX
    app-version: 4.8.0

3. 封装登录和其他方法

   1)登录方法用于获取并存储token,存储至access_token.yml中;

   2)参数”api_name“的取值是配置文件api_config.yml中的接口名称,比如:login、asset_main和loan_lend。同样封装了一个类ReadYaml,方法是取配置文件中各接口的”method、url、data、headers和expected“等;

   3)除了登录接口,其他接口的headers均需要token值,所以在处理headers时要区分登录接口和其他接口;

   4)建议:添加异常处理捕获异常,输出自定义的错误信息。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# fileName: app_api.py
from common.run_method import RunMethod
from common.read_info import ReadYaml
from common.get_log import get_log
from common.deal_token import write_token
import json
 
 
class AllApi(object):
    def __init__(self):
        self.run = RunMethod()
        self.read = ReadYaml()
        self.logger = get_log()
 
    # 登录,获取token
    def login(self, api_name):
        try:
            # 获取接口请求参数
            method = self.read.get_method(api_name)
            url = self.read.get_url(api_name)
            data = self.read.get_data(api_name)
            headers = self.read.get_headers(api_name)
            response = self.run.run_main(method, url, headers, data)
 
            # 把token值写到配置文件access_token.yml中,供其他接口调用
            write_token(response)
 
            print(json.dumps(response, indent=2, ensure_ascii=False, sort_keys=False))
            return response
        except Exception as e:
            self.logger.info("接口访问出错啦~ %s" % e)
 
    # 其他接口请求封装
    def send_request(self, api_name):
        try:
            # 获取接口请求参数
            method = self.read.get_method(api_name)
            url = self.read.get_url(api_name)
            headers = self.read.get_headers(api_name)
            # 区分Get和Post方法
            if method == "Get":
                response = self.run.run_main(method, url, headers)
            elif method == "Post":
                data = self.read.get_data(api_name)
                response = self.run.run_main(method, url, headers, data)
                # print(json.dumps(response, indent=2, ensure_ascii=False, sort_keys=False))
 
            print(json.dumps(response, indent=2, ensure_ascii=False, sort_keys=False))
            print(response["success"])
            return response
        except Exception as e:
            self.logger.info("接口访问出错啦~ %s" % e)
 
    # 获取预期结果,方便断言时直接使用
    def get_expect(self, api_name):
        try:
            # 获取配置文件中的预期结果
            expect = self.read.get_expected(api_name)
            # print(expect)
            return expect
        except Exception as e:
            self.logger.info("获取预期结果出错啦~ %s" % e)

4. 使用Pytest管理测试用例

   1)在执行所有用例之前先执行登录接口,获取token。所以把登录接口的请求放在conftest.py文件中

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# fileName: conftest.py
from API.all_api import AllApi
import pytest
from common.get_log import get_log
logger = get_log()
 
# 在执行所有用例之前先执行登录接口,获取token
@pytest.fixture(scope="session")
def init_token():
    # 正确邮箱/手机号和密码登录
    logger.info("\n ============================= 在所有用例执行之前,生成token =============================")
    all_login = AllApi()
    all_login.login("login_sandbox_phoneNumber")

  2) 把每个功能模块封装成一个类,每个用例封装成一个方法。例如资产模块的用例如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# fileName: test_asset.py
from API.all_api import AllApi
import pytest
from common.get_log import get_log
logger = get_log()
 
 
# 资产模块的测试用例
@pytest.mark.usefixtures("init_token")
class TestAsset(object):
    @pytest.fixture(scope="class")
    def init_asset(self):
        logger.info("\n ==============================【资产】测试用例开始 ==============================")
        all_request = AllApi()
        return all_request
 
    @pytest.mark.parametrize("api_name", ["asset_main"])
    def test_asset_main(self, api_name, init_asset):
        print("\n 用例名称:获取资产列表信息\n")
        res = init_asset.send_request(api_name)
        expected = init_asset.get_expect(api_name)
        # 断言1:success的值为true
        assert res['success'] == expected['success'], "success的值为: %s" % res['success']
 
 
if __name__ == "__main__":
    # pytest.main(['-v', 'test_asset.py'])
    pytest.main(['-v', 'test_asset.py', '--html=report/asset_report.html', '--self-contained-html'])

5. 添加日志模块

   1)使用配置文件配置loggers、handlers和formatters(日志器、处理器和格式器),文件名称是log.conf

[loggers]
keys=root,main
[logger_root]
level=DEBUG
handlers=consoleHandler,fileHandler
[logger_main]
level=DEBUG
qualname=main
handlers=fileHandler
[handlers]
keys=consoleHandler,fileHandler
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=fmt
args=(sys.stdout,)
[handler_fileHandler]
class=logging.handlers.RotatingFileHandler
level=DEBUG
formatter=fmt
args=('../log/Wallet_API_Test.log','a')
[formatters]
keys=fmt
[formatter_fmt]
format=%(asctime)s - %(filename)s - %(levelname)s - [line:%(lineno)d] - %(message)s

   2)使用fileConfig()函数读取日志配置文件

# fileName: get_log.py
import logging.config
import logging
 
 
# 读取日志配置文件
def get_log():
    con_log = "../configs/log.conf"
    logging.config.fileConfig(con_log)
    log = logging.getLogger()
    return log

6. 生成测试报告

   1)安装pytest-html插件。也可以使用allure插件生成测试报告,但是如果pytest版本过高,就无法识别allure插件

   2)添加“--self-contained-html”可以整合样式文件到html文档中,方便之后发送测试报告到邮箱

pytest.main(['-v', '--html=report/all_report.html', '--self-contained-html'])

7. 测试报告发送至邮箱

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# fileName: run_email.py
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
import smtplib
 
 
# 定义发邮件
def send_mail(file_path):
 
    f = open(file_path, 'rb')
    mail_body = f.read()
    f.close()
 
    smtpserver = 'smtp.qq.com'
    # 设置登录邮箱的账号和授权密码
    user = 'XXX@qq.com'
    password = ""
    sender = 'XXX@qq.com'
    # 可添加多个收件人的邮箱
    receives = ['XXX@qq.com']
    # 构造邮件对象
    msg = MIMEMultipart('mixed')
    # 定义邮件的标题
    subject = '接口自动化测试报告'
    # HTML邮件正文,定义成字典
    msg['Subject'] = Header(subject, "utf-8")
    msg['From'] = sender
    msg['To'] = ','.join(receives)
    # 构造文字内容
    text_plain = MIMEText("附件是最新的接口自动化测试报告,请查看", 'html', 'utf-8')
    msg.attach(text_plain)
    # 构造附件
    text_attr = MIMEText(mail_body, 'base64', 'utf-8')
    text_attr["Content-Type"] = 'application/octet-stream'
    text_attr['Content-Disposition'] = 'attachment; filename = "test.html"'
    msg.attach(text_attr)
 
    # 邮箱设置时勾选了SSL加密连接,进行防垃圾邮件,SSL协议端口号要使用465
    smtp = smtplib.SMTP_SSL(smtpserver, 465)
    # 向服务器标识用户身份
    smtp.helo(smtpserver)
    # 向服务器返回确认结果
    smtp.ehlo(smtpserver)
    # 登录邮箱的账号和授权密码
    smtp.login(user, password)
 
    print("开始发送邮件...")
    # 开始进行邮件的发送,msg表示已定义的字典
    smtp.sendmail(sender, receives, msg.as_string())
    smtp.quit()
    print("已发送邮件")
 
 
if __name__ == "__main__":
    report = "../testcase/report/report.html"
    send_mail(report)

8. 优化动态数据的存储

把多个登录账号信息等动态数据放到excel表格中,使用xrld和xlutils库对表格进行读取和写入。利用excel存储测试数据,实现测试数据和测试脚本的分离,方便测试数据的维护

9. 项目目录

一直在更新中,文件名可能与其他地方不一致

二、上传代码到github

1. 创建git仓库:进入项目的根目录,比如项目名是:Test,则进入Test文件夹下

命令:git init

2. 将项目内所有文件添加至仓库中

命令:git add .

3. commit到仓库

命令:git commit -m '首次提交'

4. 到github上创建Repositories后,复制仓库的地址,比如:https://github.com/XXX/Test.git

5. 将本地仓库关联到github上(很重要)

命令:git remote add origin https://github.com/XXX/Test.git

6. 上传代码到github远程仓库:其中-u是把本地master分支和远程master分支关联起来,以后再push时不需要加上-u

命令:git push -u origin master

7. 若再次上传,则要执行这三步:

    1)把Test中的文件都添加进来:git add .

    2)提交暂存区的文件,其中message是简要说明这次提交的信息:git commit -m "message"

    3)把本地文件推送到github上(有时候需要输入github账号和密码): git push origin master

8. git常用命令,可参考文章git常用命令结合若干个使用场景

9. 项目git地址:(备注:代码写的不够专业,一直在优化改进中。有兴趣的可以一起讨论)

https://github.com/ChangYixue/Test.git

三、运行测试用例的两种方法

1. 命令行模式

  1)先进入测试用例文件所在目录,然后使用“pytest”命令执行该目录下所有的测试用例文件;

  2)也可以指定某一个测试用例文件,直接在pytest后面加上文件名称即可,比如“pytest test_asset.py” 

  3)执行”某文件下的类中所有用例方法“或者”某方法“,分别用命令”pytest 文件名::类名“和”pytest 文件名::类名::方法名“

2. 在python脚本中调用pytest


 
 
  1. if __name__ == "__main__":
  2. # 若存在多个标记,则用or连接,形成一个测试集,比如'-m=assetList or test or allLists'
  3. pytest.main([ '-v', 'test_asset.py', '-m=test'])

四、重构接口自动化测试框架

1. 背景:公司开发人员帮忙重构了脚本,使配置测试环境、维护测试数据、取接口信息和处理接口依赖等更加灵活

2. 重构后的框架简介请移步:Python+Pytest+tox 接口自动化测试框架

未完待续......

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值