接口自动化框架脚手架-从Excel读取用例发起调用做断言

大家工作中统计测试用例、测试进度以及各种测试报表,或多或少离不开Excel,我们可以使用Excel公式实现自动化统计,当然也可以使用代码实现Excel数据的统计。

今天分享一款阿里巴巴开源的Excel解析工具EasyExcel,最后结合接口自动化实现一个自动化读取Excel测试用例并进行接口测试的项目。

EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。

为什么是EasyExcel?

Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的Excel也不会出现内存溢出,让使用者更加简单方便。

接口自动化框架脚手架-从Excel读取用例发起调用做断言_第1张图片


    com.alibaba
    easyexcel
    3.1.1

官网:https://easyexcel.opensource.alibaba.com/

Github:https://github.com/alibaba/easyexcel

如何使用EasyExcel?

在介绍Excel的读取之前,我们需要了解下EasyExcel操作文件的步骤,以读Excel为例可以参考下面三个步骤:

  1. 创建excel对应的实体对象
  2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器
  3. 直接读即可

如果我们的自动化框架设计思路是在Excel中保存我们的用例,那么假如用例内容包括以下内容。

接口自动化框架脚手架-从Excel读取用例发起调用做断言_第2张图片

我们首先新建一个TestCase类,只有四个字段:no、api、request、expect。

注意: Java类中的属性字段顺序和Excel中的表头字段顺序一致, 也可以不写@ExcelProperty

package cn.qa.excelUtil.entity;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

@Data
public class TestCase {

    // 根据Excel中指定列名或列的索引读取
    @ExcelProperty(value = "no", index = 0)
    private String no;

    @ExcelProperty(value = "api", index = 1)
    private String api;

    @ExcelProperty(value = "request", index = 2)
    private String request;

    @ExcelProperty(value = "expect", index = 3)
    private String expect;
}

另外写一个Excel文件统一存放路径的TestFileUtil,我们将测试Excel文件放到特定文件夹下面。

package cn.qa.excelUtil.util;

import java.io.File;
import java.io.InputStream;

public class TestFileUtil {

    public static InputStream getResourcesFileInputStream(String fileName) {
        return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName);
    }

    public static String getPath() {
        return TestFileUtil.class.getResource("/").getPath();
    }

    public static File createNewFile(String pathName) {
        File file = new File(getPath() + pathName);
        if (file.exists()) {
            file.delete();
        } else {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
        }
        return file;
    }

    public static File readFile(String pathName) {
        return new File(getPath() + pathName);
    }

    public static File readUserHomeFile(String pathName) {
        return new File(System.getProperty("user.home") + File.separator + pathName);
    }
}

读Excel

写法1:简单读Excel

  // since: 3.0.0-beta1
        String fileName = TestFileUtil.getPath()+ "demo"  + File.separator + "TestCase.xlsx";
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
        // 这里每次会读取100条数据 然后返回过来 直接调用使用数据就行
        EasyExcel.read(fileName, TestCase.class, new PageReadListener(dataList -> {
            for (TestCase TestCase : dataList) {
                log.info("读取到一条数据{}", JSON.toJSONString(TestCase));
            }
        })).sheet().doRead();

写法2:读取Excel数据并临时存储缓存

String fileName = TestFileUtil.getPath() + "demo" + File.separator + "TestCase.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, TestCase.class, new ReadListener() {
    /**
     * 单次缓存的数据量
     */
    public static final int BATCH_COUNT = 100;
    /**
     *临时存储
     */
    private List cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    @Override
    public void invoke(TestCase data, AnalysisContext context) {
        cachedDataList.add(data);
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
    }
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", cachedDataList.size());
        log.info("存储数据库成功!");
    }
}).sheet().doRead();

写Excel

方法1:最简单的写法一,在已有Excel写入数据

package cn.qa.WriteExcelUtil;

import cn.qa.excelUtil.entity.TestCase;
import cn.qa.excelUtil.util.TestFileUtil;
import com.alibaba.excel.EasyExcel;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class WriteExcelUtil {

    public static List getTestCaseData(){
        List testCases = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            TestCase testCase = TestCase.builder()
                    .no(String.valueOf(i))
                    .api("api_" + String.valueOf(i))
                    .request("testRequest")
                    .expect("success")
                    .build();
            testCases.add(testCase);
        }
        return testCases;
    }


    public static void main(String[] args) {
        String filename = TestFileUtil.getPath() + "demo" + File.separator + "TestCase.xlsx";

        // 向Excel中写入数据 也可以通过 head(Class) 指定数据模板
        EasyExcel.write(filename, TestCase.class)
                .sheet("Case")
                .doWrite(getTestCaseData());
    }

}

接口自动化框架脚手架-从Excel读取用例发起调用做断言_第3张图片

方法2:最简单的写法二,新建Excel并写入

public static void main(String[] args) {
        String filename = TestFileUtil.getPath() + "demo" + File.separator + "TestCase.xlsx";
        // 创建ExcelWriter对象
        ExcelWriter excelWriter = EasyExcel.write(filename, TestCase.class).build();
        // 创建Sheet对象
        WriteSheet writeSheet = EasyExcel.writerSheet("Case").build();
        // 向Excel中写入数据
        excelWriter.write(getTestCaseData(), writeSheet);
        // 关闭流
        excelWriter.finish();
    }

结合自动化框架实现自动化测试

实现思路:读取Excel中的测试用例,通过接口的统一发起端调用接口,然后对接口返回信息作断言。

一、接口发起端Invoke代码如下(与之前的代码做了改动,即给invokeProxy增加返回值,因为后面要做断言):

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Invoke {

        public Object invokeProxy(String serviceName, String api, String request) {
        try {
            Class serviceClass = Class.forName(serviceName);
            Object service = serviceClass.getDeclaredConstructor().newInstance();
            Method method = serviceClass.getMethod(api, String.class);
           return method.invoke(service, request);
        } catch (ClassNotFoundException e){
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }
}

二、读自动化用例代码

package cn.qa.excelUtil;

import cn.qa.excelUtil.entity.TestCase;
import cn.qa.excelUtil.util.TestFileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class ReadCaseUtil {

    public static List readCase(String caseFile){
        String fileName = TestFileUtil.getPath()+ "demo"  + File.separator + caseFile;
        List result = new ArrayList<>();
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(fileName, TestCase.class, new PageReadListener(dataList -> {
            for (TestCase TestCase : dataList) {
                result.add(TestCase);
            }
        })).sheet().doRead();
        return result;
    }
}

三、开发用例

@Test
public void testInvokeCase(){

    String CreateServiceName = "cn.qa.reflect.demo.service.CreateService";
    String QueryServiceName = "cn.qa.reflect.demo.service.QueryService";

    // Step1: 读自动化用例
    List testCaseList = ReadCaseUtil.readCase("TestCase.xlsx");
    for (TestCase testCase: testCaseList){
        if (testCase.getApi().equals("create")){
            // Step2: 发起服务调用
           Object response = invokeProxy(CreateServiceName, testCase.getApi(), testCase.getRequest());
            // Step3: 断言
            Assert.assertTrue(response.toString().contains(testCase.getExpect()));
        }
        if (testCase.getApi().equals("query")){

            Object response = invokeProxy(QueryServiceName, testCase.getApi(), testCase.getRequest());
            Assert.assertTrue(response.toString().contains(testCase.getExpect()));
        }
    }
}

软件测试工程师自学教程:

这才是2022最精细的自动化测试自学教程,我把它刷了无数遍才上岸字节跳动,做到涨薪20K【值得自学软件测试的人刷】

接口性能测试 — 软件测试人必会618实战场景分析

软件测试工程师月薪2W以上薪资必学技能 — Python接口自动化框架封装.

美团面试真题_高级测试25K岗位面试 — 软件测试人都应该看看

测试开发之全面剖析自动化测试平台 — 软件测试人的必经之路

软件测试必会_Jmeter大厂实战 — 仅6步可实现接口自动化测试

Jmeter实战讲解案例 — 软件测试人必会

我推荐一个【Python自动化测试交流群:746506216】,大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,助你快速进阶Python自动化测试/测试开发,走向高薪之路。

喜欢软件测试的小伙伴们,如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一 键三连哦!

你可能感兴趣的:(IT,职场经验,软件测试,自动化,运维,功能测试,性能测试,软件测试)