【测试沉思录】23. 如何实现基于场景的接口自动化测试用例?

news2024/11/22 16:24:47

作者:陈爱娇 编辑:毕小烦

自动化本身是为了提高工作效率,不论选择何种框架,何种开发语言,我们最终想实现的效果,就是让大家用最少的代码,最小的投入,完成自动化测试的工作。

基于这个想法,我们的接口自动化测试思路如下:

  1. 不变的内容全部通过配置化来实现,比如:脚本执行的环境、请求的 HOST、URL 路径、测试数据等;
  2. 环境和数据关联变更:依据不同的环境,选择不同的配置及对应的测试数据;
  3. 抽取公共方法,避免冗余代码;
  4. 场景化的用例,实现可配置化;
  5. 数据驱动;

一. 问题

在做自动化的过程中,不能只考虑单接口的脚本,也要考虑场景化的用例。 场景化的用例不需要每个步骤都去校验所有的数据,可能更多看重串联后的最终效果

那什么是场景用例?

其实就是多个接口组成的业务场景,常规写代码的做法是,先调用接口 1,验证结果, 再调用接口 2,再继续接口 3,… 等等; 在测试场景中,可能只是各个接口的入参不一样,或者是调用的接口不一样。这样代码写起来就会冗余。

比如:

def test_01(self):
    # step 01
    result1 = PackDemo().getTest()
    assert result1 == 4

    # step02
    result2 = PackDemo2().getTest2("name")
    assert result2 == 'name'
    
    # step03
    result3 = DemoApi().getTest()
    assert result3 == 2

这样的用例,对于简单的接口没什么问题,但是对于复杂的接口,校验逻辑比较多,或者入参比较多,实现的方式就过于单一了。且不同场景的话,每个都要更改调用的步骤和返回值,场景越多冗余越多。

如果使用配置化的方式,每次从配置文件中动态加载配置的场景用例, 而且能够做到加载后做对应的断言,那该多好。

怎么做呢?

咱们看看一些核心的实现。

二. 方案

2.1 项目结构

项目结构如下:

img

采用当前比较流行的 Python + Pytest + Allure 来实现,具体结构不做展开。

2.2 场景用例的配置数据

# test_scenario.json
{
  "test_01": {
    "step_1": {  ---- 步骤节点名称,可自定义
      "packagePath": "api", --- 这个步骤要运行的方法所属类的包路径
      "class": "DemoApi", --- 这个步骤要运行的方法所属类名称
      "method": "getTest", --- 这个步骤要运行的方法名称
      "request": null,  ---这个步骤运行的方法入参
      "response": 2, ---这个步骤运行的结果,可以是一个值,或者对象
      "verify": { --- 数据校验的节点
        "type": 1, ---数据校验的类型
        "keys": null  ---如果是校验的特定字段,这里需要输入部分校验的字段
      }
    },
    "step_2": {
      "packagePath": "api.demo",
      "class": "PackDemo",
      "method": "getTest2",
      "request": "request -> name",
      "response": 6,
      "verify": {
        "type": 1,
        "keys": null
      }
    },
    "step_3": {
      "packagePath": "api.demo",
      "class": "PackDemo2",
      "method": "getTest3",
      "request": {
        "name": "param-name",
        "num_list": ["a", "b", "c"]
      },
      "response": 8,
      "verify": {
        "type": 1,
        "keys": null
      }
    }
  }
}

2.3 动态加载类

在我们配置了以上的测试场景的数据后,我们希望在用例执行的过程中,通过获取我们的配置,能够动态的加载数据文件中提到的方法,并执行对应的方法,那这个过程的实现我们主要通过如下的动态加载类来实现。

# DynamicLoad.py 
# 部分主要的摘录如下
 def __load_module(self):
        """
        加载对应路径下的模块
        :param package_path: 包路径
        :param class_name: 类名称
        :return:
        """
        return importlib.import_module("." + self.class_name, package=self.package_path)

def __getClassInstance(self):
    """
    加载对应的模块下的类,并返回对应类的实例 
    :param module_name: 对应的模块
    :param class_name:
    :return:
    """
    self.my_module = self.__load_module()
    self.my_class = getattr(self.my_module, self.class_name)()
    return self.my_class

def execMethod(self, method, *args):
    """
    加载对应类下的方法 
    :param instance: 对应的实例
    :param method: 要执行的方法
    :return:
    """
    result = getattr(self.__getClassInstance(), method)(*args)
    return result

有了以上动态加载的方法后,在执行场景用例时,依据上述的方法,就可以执行测试文件中提到的方法。

2.4 场景分析类

在场景用例的测试数据中,除了需要解析需要执行的类、方法外,还要解析文件中涉及到的出入参及数据比对方式,因此,这里还需要一个场景分析类,来解析数据文件中关于具体执行过程的配置。

 #ScenariosAnalyze.py
 def analyse_exe_scenario(self, case_data):
        step_result = {}
        summary = True
        for i in case_data:
            instance = DynamicLoad(case_data[i]['packagePath'], case_data[i]['class'])
            if case_data[i]['request'] is not None:
                result = instance.execMethod(case_data[i]['method'], case_data[i]['request'])
            else:
                result = instance.execMethod(case_data[i]['method'])
            if case_data[i]['verify'] is not None:
                compare_type = case_data[i]['verify']['type']
                keys = case_data[i]['verify']['keys']
                step_compare_result = DataCompare().compare_type(compare_type=compare_type, actual=result,
                                                                 expect=case_data[i]['response'], keys=keys)
                if not step_compare_result:
                    summary = False
            step_result[i] = step_compare_result
        step_result['summary'] = summary
        return step_result

2.5 用例实现

# @File : test_scenario.py

class TestScenario:

    @allure.story('场景用例01')
    @allure.severity(allure.severity_level.BLOCKER)
    @pytest.mark.smoke
    def test_01(self):
        result = None
        case_data = self.test_data_json['test_01']
        result = self.scenario_analyze.analyse_exe_scenario(case_data)
        assert result['summary'] is True

通过上述简单的脚本调用,就可以完成一个场景用例的测试了。

三. 小结

以上就是场景用例配置化的实现思路。

它的优点是:

  1. 配置化: 一切固定不变的内容全部配置化,最终达到:一个环境配置文件,一套脚本,几套测试数据,依据环境的不同选择不同的测试数据执行对应的测试脚本;
  2. 门槛低: 因为配置化,测试同学只要把测试数据文件中的关键节点配置好,然后在脚本中写下调用方法,就完成用例编写了;
  3. 好扩展: 在后续的实现中,可以将这些配置全部页面化,包括环境、数据、脚本,达到无代码开发的目的;

缺点当然是不够灵活,所以没有完美的方案,只有合适的,以上,仅供大家参考。

(完)

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

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

相关文章

EMQ 宣布推出 LF Edge eKuiper 全新 Logo 标识

全球领先的开源物联网数据基础设施软件供应商 EMQ 映云科技宣布,即日起,将正式启用全新的 LF Edge eKuiper(以下简称 eKuiper)产品 Logo。焕然一新的 eKuiper 产品 Logo 标志着 EMQ 在不断提升品牌全球化战略之上,对于打造高性能、高可用、高安全的世界级开源软件产品的极致追求…

关于密码设置

使用一个密码并在数据泄漏时保护自己的其它账号 关于密码 现在好多软件,好多网站都需要我们设置密码,这个时候我们的处理办法一般分为2种。 对不同的软件设置不同的密码,这种理论上是最安全的,但是记不住啊,所以不实…

Letbook Cookbook题单——数组二分与双指针

Letbook Cookbook题单——数组二分与双指针 1. 两数之和 难度:简单 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。…

Locust学习记录5-任务属性【Task】

Task 当负载测试开始时,将为每个模拟用户创建一个User类的实例,他们将开始在自己的绿色线程中运行。当这些用户运行时,他们选择他们执行的任务,休眠一段时间,然后选择一个新任务。 这些任务时普通的python可调用文件…

windows环境下python连接openGauss数据库

文章目录一、python 介绍二、Python下载及安装三、openGauss Connectors (Psycopg2) 介绍四、openGauss Connectors (Psycopg2)下载并初始化五、连接并访问openGauss数据库六、问题总结(FAQ)一、python 介绍…

Maven学习笔记

Maven Maven是一个项目管理工具依赖管理 传统工程中我们直接把jar包放在项目中maven工程真正的jar包放在仓库中,项目中只防止jar包的坐标 一键构建 maven自身集成了tomcat插件,可以对项目进行编译、测试、打包、安装、发布等操作 仓库的种类 本地仓库远程…

计算机毕业论文java毕业设计选题源代码ssm校园兼职系统|求职招聘系统

💖💖更多项目资源,最下方联系我们✨✨✨✨✨✨ 目录 Java项目介绍 资料获取 Java项目介绍 3.1 需求分析 校园兼职系统主要是为了提高工作人员的工作效率和更方便快捷的满足用户,更好存储所有数据信息及快速方便的检索功能&am…

人工智能与机器学习

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 人工智能与机器学习📝人工智能相关概念☞什么是人工智能、机器学习、深度学习☞人工智能发…

思科防火墙NAT——实验

作者简介:一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 1.实验 防火墙配置 其他配置 前言 本章将会讲解思科NAT配置的…

记一次 .NET 某工控软件 内存泄露分析

一:背景 1.讲故事 上个月 .NET调试训练营 里的一位老朋友给我发了一个 8G 的dump文件,说他的程序内存泄露了,一时也没找出来是哪里的问题,让我帮忙看下到底是怎么回事,毕竟有了一些调试功底也没分析出来,…

Hash与ZSet的常用命令以及其底层数据结构

目录hash类型命令hsethgethmsethmgethgetallhsetnxhdelhexitshincrby与hincrbyfloathkeys与hvalshlenhstrlen有序set型命令zaddzrange 与zrevrangezrangebyscore与zrevrangebyscorezcardzcountzscorezincrbyzrank 与 zrevrankzremzremrangebyrankzremrangebyscorezrangebylexzl…

MySQL学习笔记(十四)索引失效有哪些情况?

1.表和数据 CREATE TABLE t_user (id bigint(32) NOT NULL AUTO_INCREMENT,user_name varchar(40) DEFAULT NULL COMMENT 用户名,user_code varchar(40) DEFAULT NULL COMMENT 用户编号,phone varchar(11) DEFAULT NULL COMMENT 电话,age tinyint(3) DEFAULT NULL COMMENT 年龄…

微机----------------中断技术

目录 中断概述中断处理过程中断请求中断响应中断处理8086/8088中断中断类型中断优先级顺序⭐中断向量表中断处理过程中断概述 中断: 当CPU执行程序时,由于随机的事件引起CPU暂时停止正在执行的程序,而转去执行中断服务程序,处理完后又返回被终止的程序断点处继续执行,这个…

Bug系列路径规划算法原理介绍(四)——I-BUG 算法

本系列文章主要对Bug类路径规划算法的原理进行介绍,在本系列的第一篇文章中按照时间顺序梳理了自1986年至2018年Bug类路径规划算法的发展,整理了13种BUG系列中的典型算法,从本系列的第二篇文章开始依次详细介绍了其中具有代表性的BUG1、BUG2、…

数学基础从高一开始2、集合间的基本关系

高中数学人教 A 版必修一 集合间的基本关系 学习目标: (1)初步理解集合之间的包含与相等的含义; (2)能识别给定集合的子集和真子案,了解空集含义: (3)能进行自然语言、图形语言(Venn 图)、符号语言闻的转换,积萦抽象思维的经验, …

递归算法(及其衍生算法:缓存,分治,回溯)

文章目录一、初识递归二、缓存三、分治四、回溯一、初识递归 递归函数 终止条件 递归关系 终止条件: 当大问题被拆解成能轻松解决的小问题时,运行终止条件中的逻辑 递归关系: 定义如何将大问题拆解为小问题 例子:小名跑步。 …

这十一个副业在家就可以完成,疫情在家也有收入,建议收藏

2022年,谁还没有副业? 经过两年的疫情,我们都知道没有钱是一件非常不舒服的事情。现在的做法是:主营业务要求稳定,副业要求发展;好好发展副业是硬道理。 在过去的两年里,我一直在探索副业项目…

(六)Vue之数据代理

文章目录回顾Object.defineProperty方法数据属性valueenumerablewritableconfigurable访问器属性get()set(v: any)何为数据代理Vue中的数据代理Vue学习目录上一篇:(六)Vue之MVVC 回顾Object.defineProperty方法 Object.defineProperty方法的…

Chain Surfase Test - java 链表经典 OJ 面试题 - 巨细

效果图 LeetCode - 206. 反转链表 代码如下: /** Definition for singly-linked list. public class ListNode { int val;ListNode next;ListNode() {}ListNode(int val) { this.val val; }ListNode(int val, ListNode next) { this.val val; this.next next; …

K-Means++代码实现

K-Means代码实现 数据集 https://download.csdn.net/download/qq_43629083/87246495 import pandas as pd import numpy as np import random import math %matplotlib inline from matplotlib import pyplot as plt# 按文件名读取整个文件 data pd.read_csv(data.csv)class…