接口测试返回参数的自动化对比!

news2024/9/21 14:34:18

引言

在现代软件开发过程中,接口测试是验证系统功能正确性和稳定性的核心环节。接口返回参数的对比不仅是确保接口功能实现的手段,也是测试过程中常见且重要的任务。为了提高对比的效率和准确性,我们可以通过自动化手段实现这一过程。本文将介绍接口测试返回参数自动化对比的原理,展示如何使用 Python 和 MySQL 实现对比功能,并提供最佳实践的建议,帮助读者在实际项目中应用这些技术。

自动化对比的原理

接口测试返回参数的自动化对比涉及以下几个步骤:

  1. 提取和存储预期结果:在测试用例设计阶段,定义接口调用的预期返回结果,并将其存储在文件或数据库中。

  2. 执行接口调用:通过自动化测试脚本执行接口调用,获取实际的返回结果。

  3. 结果比对:将实际返回的结果与预期结果进行比对,以确认接口是否满足需求。

自动化对比的工作流程

  1. 准备测试数据:包括请求参数和预期返回结果。

  2. 执行测试用例:发送请求并接收响应。

  3. 对比实际返回的结果和预期结果:通过编写自动化脚本对比返回的参数。

  4. 记录对比结果:将对比结果存储到数据库中,并生成测试报告。

  5. 数据清理:在测试完成后对数据进行清理以维护数据库的健康状态。

数据库设计与实现

为了实现自动化对比,我们选择 MySQL 数据库来存储测试执行信息和对比结果。以下是数据库设计方案及其实现细节。

数据库表设计

1. 测试执行表

存储每次测试执行的信息。

CREATE TABLE test_execution (
    execution_id VARCHAR(36) PRIMARY KEY,
    test_case_id INT NOT NULL,
    execution_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    status VARCHAR(10) NOT NULL
);
2. 接口调用表

存储每次接口调用的信息。

CREATE TABLE api_call (
    call_id VARCHAR(36) PRIMARY KEY,
    execution_id VARCHAR(36),
    api_endpoint VARCHAR(255) NOT NULL,
    request_params JSON,
    response_data JSON,
    compare_result VARCHAR(10),
    FOREIGN KEY (execution_id) REFERENCES test_execution(execution_id)
);
3. 对比结果表

存储每次对比的详细信息。

CREATE TABLE compare_result (
    compare_id VARCHAR(36) PRIMARY KEY,
    call_id VARCHAR(36),
    field_name VARCHAR(255),
    expected_value TEXT,
    actual_value TEXT,
    match_result VARCHAR(10),
    FOREIGN KEY (call_id) REFERENCES api_call(call_id)
);

数据库操作示例

以下是插入测试执行记录、接口调用记录和对比结果记录的代码示例:

import mysql.connector
from uuid import uuid4

# 数据库上下文管理器
class Database:
    def __enter__(self):
        self.connection = mysql.connector.connect(
            host="localhost",
            user="root",
            password="password",
            database="test_db"
        )
        self.cursor = self.connection.cursor()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.connection.commit()
        self.cursor.close()
        self.connection.close()

# 插入测试执行记录
def insert_test_execution(test_case_id):
    execution_id = str(uuid4())
    with Database() as db:
        db.cursor.execute(
            "INSERT INTO test_execution (execution_id, test_case_id, status) VALUES (%s, %s, %s)",
            (execution_id, test_case_id, 'running')
        )
    return execution_id

# 插入接口调用记录
def insert_api_call(execution_id, api_endpoint, request_params, response_data, compare_result):
    call_id = str(uuid4())
    with Database() as db:
        db.cursor.execute(
            "INSERT INTO api_call (call_id, execution_id, api_endpoint, request_params, response_data, compare_result) VALUES (%s, %s, %s, %s, %s, %s)",
            (call_id, execution_id, api_endpoint, json.dumps(request_params), json.dumps(response_data), compare_result)
        )
    return call_id

# 插入对比结果记录
def insert_compare_result(call_id, field_name, expected_value, actual_value, match_result):
    compare_id = str(uuid4())
    with Database() as db:
        db.cursor.execute(
            "INSERT INTO compare_result (compare_id, call_id, field_name, expected_value, actual_value, match_result) VALUES (%s, %s, %s, %s, %s, %s)",
            (compare_id, call_id, field_name, expected_value, actual_value, match_result)
        )

动态参数的过滤

在接口测试中,动态参数(如时间戳、随机数等)可能会导致对比结果的不一致。为了提高对比的准确性,需要在对比过程中对这些动态参数进行过滤。

动态参数过滤的实现

以下是动态参数过滤的示例代码,过滤掉返回结果中的动态字段:

import requests
import json

# 动态参数过滤函数
def filter_dynamic_params(response_data: dict, exclude_keys: list) -> dict:
    """
    过滤动态参数,排除不需要对比的字段。
    """
    return {k: v for k, v in response_data.items() if k not in exclude_keys}

# 动态参数列表
dynamic_params = ['timestamp', 'token', 'session_id']

# 执行接口调用并对比结果
def call_and_compare(execution_id, url, params, expected_response):
    response = requests.post(url, json=params)
    actual_response = response.json()
    filtered_response = filter_dynamic_params(actual_response, dynamic_params)
    filtered_expected_response = filter_dynamic_params(expected_response, dynamic_params)
    compare_result = 'match' if filtered_expected_response == filtered_response else 'mismatch'
    call_id = insert_api_call(execution_id, url, params, filtered_response, compare_result)

    for key in filtered_expected_response:
        if key in filtered_response:
            match_result = 'match' if filtered_expected_response[key] == filtered_response[key] else 'mismatch'
            insert_compare_result(call_id, key, filtered_expected_response[key], filtered_response[key], match_result)

# 测试用例
def test_interface():
    execution_id = insert_test_execution(1)
    url = "http://api.example.com/login"
    params = {"username": "test", "password": "test"}
    expected_response = {"status": "success", "timestamp": "ignore"}
    call_and_compare(execution_id, url, params, expected_response)

    # 更新测试执行状态
    with Database() as db:
        db.cursor.execute("UPDATE test_execution SET status = %s WHERE execution_id = %s", ('completed', execution_id))

if __name__ == "__main__":
    test_interface()

集成对比结果的报告内容

在测试执行完成后,我们可以生成一个对比结果报告,以展示测试的执行情况和结果。

生成报告的代码示例
from jinja2 import Template

# 生成对比结果报告
def generate_report(execution_id):
    with Database() as db:
        db.cursor.execute("""
            SELECT a.api_endpoint, a.request_params, a.response_data, a.compare_result, c.field_name, c.expected_value, c.actual_value, c.match_result
            FROM api_call a
            JOIN compare_result c ON a.call_id = c.call_id
            WHERE a.execution_id = %s
        """, (execution_id,))
        results = db.cursor.fetchall()

    # Jinja2 模板
    template_str = """
    <!DOCTYPE html>
    <html>
    <head><title>测试对比结果报告</title></head>
    <body>
        <h1>测试对比结果报告</h1>
        <p><strong>测试执行ID:</strong>{{ execution_id }}</p>
        <table border="1">
            <tr>
                <th>接口地址</th>
                <th>请求参数</th>
                <th>返回数据</th>
                <th>对比结果</th>
                <th>字段名称</th>
                <th>预期值</th>
                <th>实际值</th>
                <th>匹配结果</th>
            </tr>
            {% for row in results %}
            <tr>
                <td>{{ row.api_endpoint }}</td>
                <td>{{ row.request_params }}</td>
                <td>{{ row.response_data }}</td>
                <td>{{ row.compare_result }}</td>
                <td>{{ row

.field_name }}</td>
                <td>{{ row.expected_value }}</td>
                <td>{{ row.actual_value }}</td>
                <td>{{ row.match_result }}</td>
            </tr>
            {% endfor %}
        </table>
    </body>
    </html>
    """

    template = Template(template_str)
    html_report = template.render(execution_id=execution_id, results=results)

    # 保存报告到文件
    with open(f'report_{execution_id}.html', 'w') as f:
        f.write(html_report)

对比数据的清理

测试完成后,需要对比数据进行清理,以保持数据库的健康状态。以下是手动和自动数据清理的示例代码。

手动清理数据
def manual_cleanup(execution_id):
    with Database() as db:
        db.cursor.execute("DELETE FROM compare_result WHERE call_id IN (SELECT call_id FROM api_call WHERE execution_id = %s)", (execution_id,))
        db.cursor.execute("DELETE FROM api_call WHERE execution_id = %s", (execution_id,))
        db.cursor.execute("DELETE FROM test_execution WHERE execution_id = %s", (execution_id,))
自动清理数据
import schedule
import time

# 自动清理任务
def auto_cleanup():
    with Database() as db:
        db.cursor.execute("""
            DELETE FROM compare_result WHERE compare_id IN (
                SELECT compare_id FROM compare_result
                WHERE compare_id NOT IN (
                    SELECT compare_id FROM api_call WHERE execution_id IN (
                        SELECT execution_id FROM test_execution WHERE status = 'completed'
                    )
                )
            )
        """)
        db.cursor.execute("""
            DELETE FROM api_call WHERE call_id IN (
                SELECT call_id FROM api_call
                WHERE call_id NOT IN (
                    SELECT call_id FROM compare_result
                )
            )
        """)
        db.cursor.execute("""
            DELETE FROM test_execution WHERE status = 'completed' AND execution_id NOT IN (
                SELECT execution_id FROM api_call
            )
        """)

# 设置定时任务
schedule.every().day.at("00:00").do(auto_cleanup)

while True:
    schedule.run_pending()
    time.sleep(1)

结论

在本文中,我们详细探讨了接口测试返回参数的自动化对比方法,包括动态参数的过滤、对比结果的报告生成以及对比数据的清理。通过合理的工具和技术手段,可以显著提高接口测试的效率和效果。希望本文提供的实践经验和代码示例能帮助从事接口测试的技术人员在实际项目中更好地应用自动化对比技术,提高测试的质量和效率。

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1925579.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

android CameraX构建相机拍照

Android CameraX 是一个 Jetpack 支持库&#xff0c;旨在简化相机应用的开发工作。它提供了一致且易用的API接口&#xff0c;适用于大多数Android设备&#xff0c;并可向后兼容至Android 5.0&#xff08;API级别21&#xff09;。 CameraX解决了在多种设备上实现相机功能时所遇…

LLM代理应用实战:构建Plotly数据可视化代理

如果你尝试过像ChatGPT这样的LLM&#xff0c;就会知道它们几乎可以为任何语言或包生成代码。但是仅仅依靠LLM是有局限的。对于数据可视化的问题我们需要提供一下的内容 描述数据:模型本身并不知道数据集的细节&#xff0c;比如列名和行细节。手动提供这些信息可能很麻烦&#…

javascipt学习笔记一

JavaScript基础day1 一、编程语言 1.编程 编程&#xff1a;就是让计算机为解决某个问题而使用某种编程设计语言编写程序代码&#xff0c;最终得到结果的过程 计算机程序&#xff1a; 就是计算机所执行的一系列的指令集合。 2.计算机语言 计算机语言指的是用于人与计算机之间通…

Manim的代码练习02:在manim中Dot ,Arrow和NumberPlane对象的使用

Dot&#xff1a;指代点对象或者表示点的符号。Arrow&#xff1a;指代箭头对象&#xff0c;包括直线上的箭头或者向量箭头等。NumberPlane&#xff1a;指代数轴平面对象&#xff0c;在Manim中用来创建包含坐标轴的数学坐标系平面。Text&#xff1a;指代文本对象&#xff0c;用来…

国产数据库VastBase与C/C++程序适配

背景 2022年底的项目&#xff0c;记录一下。 某项目后台使用C程序开发&#xff0c;使用的是OCI连接Oracle数据库。现需要做去O国产化适配改造。 本文聊聊C/C应用程序如何使用VastBase替换Oracle。 编译适配 开发包获取 从VastBase官方或接口人处获取OCI开发包&#xff0c;包含…

品牌产业出海指南如何搭建国际化架构的跨境电商平台?

在“品牌&产业出海指南 – 成功搭建跨境电商平台”系列中&#xff0c;我们将从电商分销系统、跨境平台商城/多商户商城系统和国际化架构三个方面对帮助您梳理不同平台模式的优缺点、应用场景、开发重点和运营建议。 在“品牌&产业出海指南 – 成功搭建跨境电商平台”系…

verITAS:大规模验证图像转换

1. 引言 斯坦福大学Trisha Datta、Binyi Chen 和 Dan Boneh 2024年论文《VerITAS: Verifying Image Transformations at Scale》&#xff0c;开源代码实现见&#xff1a; https://github.com/zk-VerITAS/VerITAS&#xff08;RustPython&#xff09; 依赖https://github.com/a…

Java的高级特性

类的继承 继承是从已有的类中派生出新的类&#xff0c;新的类能拥有已有类的属性和行为&#xff0c;并且可以拓展新的属性和行为 public class 子类 extends 父类{子类类体 } 优点 代码的复用 提高编码效率 易于维护 使类与类产生关联&#xff0c;是多态的前提 缺点 类缺乏独…

纯vue+js实现数字0到增加到指定数字动画效果功能

关于数字增加动画效果网上基本上都是借助第三方插件实现的,就会导致有的项目安装插件总会出问题,所有最好使用原生vue+js实现,比较稳妥 纯vue+js实现数字0到增加到指定数字动画效果功能 vue+js 实现数字增加动画功能 效果图 其中,关于数字变化的间隔时间,延时效果都可…

Linux环境下激活使用Navicat

Linux环境下激活使用Navicat 解压navicat15-premium-linux.zip文件&#xff0c;存放目录自行定义&#xff0c;此处我解压到/home/admin/Downloads&#xff0c;下载地址&#xff1a;https://www.123pan.com/s/hyS7Vv-zJCR.html # 在桌面创建临时目录 mkdir ~/Desktop/navicat…

Flutter和React Native(RN)的比较

Flutter和React Native&#xff08;RN&#xff09;都是用于构建跨平台移动应用程序的流行框架。两者都具有各自的优势和劣势&#xff0c;选择哪个框架取决于您的具体需求和项目。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 以下是…

算法学习笔记(8.5)-零钱兑换问题二

目录 Question&#xff1a; 动态规划思路&#xff1a; 代码实现&#xff1a; 空间优化代码 Question&#xff1a; 给定n种硬币&#xff0c;第i种硬币的面值为coins[i-1],目标金额为amt&#xff0c;每种硬币可以重复选取&#xff0c;问凑出目标金额的硬币组合数量。 动态规划思路…

教你如何白嫖ioDraw

ioDraw推出了这个活动&#xff0c;大家看看~ 领取页面 邀请奖励 您和好友都将获得7天的会员权益 邀请攻略 活动介绍 1. 每成功邀请一个新用户&#xff0c;邀请者与被邀请者均可获得7天会员 2. 每年最高可得350天 3. 新用户是指首次登录ioDraw的用户 获取邀请链接步骤 1. 浏…

VS2019配置OpenGL的库

OpenGL环境的配置&#xff08;GLUT安装教程&#xff09;_opengl官网-CSDN博客 我是根据这篇来配置的&#xff0c;然后&#xff1a; 引用的头文件不是<OpenGL/glut.h>而是<GL/glut.h>&#xff0c;然后就可以运行了。

CCSI: 数据无关类别增量学习的持续类特定印象| 文献速递-基于深度学习的多模态数据分析与生存分析

Title 题目 CCSI: Continual Class-Specific Impression for data-free class incremental learning CCSI: 数据无关类别增量学习的持续类特定印象 01 文献速递介绍 当前用于医学影像分类任务的深度学习模型表现出令人鼓舞的性能。这些模型大多数需要在训练之前收集所有的…

【tomcat】Tomcat如何扩展Java线程池原理

池化技术 在后端中&#xff0c;对于经常使用池化就是来提升系统性能&#xff0c;比如数据库连接池、线程池连接池等&#xff0c;本质都是利用空间换时间的来提升性能&#xff0c;用来避免资源的频繁创建和销毁&#xff0c;以此提高资源的复用率&#xff0c;所以合理设置系统所…

springboot个人健康信息管理小程序-计算机毕业设计源码

摘要 在当今这个数字化、信息化的时代&#xff0c;个人健康管理已成为人们生活中不可或缺的一部分。随着生活节奏的加快&#xff0c;越来越多的人开始关注自己的身体状况&#xff0c;希望能够及时了解并调整自己的生活习惯&#xff0c;以达到最佳的健康状态。为此&#xff0c;我…

Codeforces Round 957 (Div. 3) D,F

D. Test of Love 很容易想到dp&#xff0c;对于dp的转移方程也比较好写&#xff0c;当前点只能从当前点前面m个点转移过来&#xff0c;那么思考转移的条件&#xff0c;对于前面的点 j j j &#xff0c;如果 j j j 是水并且 i i i 和 j j j 不相邻&#xff0c;那么不能进行转…

初始化列表和explicit关键字和static成员

初始化列表 1.初始化和赋值的概念&#xff1a; 首先我们先来了解一下成员变量初始化和赋值的概念&#xff0c;初始化是是对成员变量进行一次赋值&#xff0c;注意是只能一次赋值&#xff0c;而赋值是可以多次进行赋值的。 2.初始化列表的引出&#xff1a; 我们知道了初始化…

ftp pool 功能分析及 golang 实现

本文探究一种轻量级的 pool 实现 ftp 连接。 一、背景 简要介绍&#xff1a;业务中一般使用较多的是各种开源组件&#xff0c;设计有点重&#xff0c;因此本文探究一种轻量级的 pool 池的思想实现。 期望&#xff1a;设置连接池最大连接数为 N 时&#xff0c;批量执行 M 个 F…