zoukankan      html  css  js  c++  java
  • junit5|并行测试

    一、需求背景

    1、自动化测试:一个自动化测试脚本有成千上万条用例,每次执行的时间在小时级别,leader说为了能先于用户知道线上的问题,能否加快脚本的执行速度

    2、功能测试:不使用jmeter等工具,使用junit5实现来测试接口是否存在线程安全以及分布式线程安全问题,是否有做幂等性处理

    3、功能测试:来测试增删改查接口,同时发送请求,检查是否有数据库安全问题,即是否会引起锁表,而引起接口超时

    二、解决方案

    junit5的并行测试

    三、前提条件

    自身的测试用例独立,用例之间没有依赖关系,容错性好

    四、具体步骤

    1、在src/main/resources/路径下新建文件junit-platform.properties

     2、在文件中添加如下内容

    #是否允许并行执行true/false
    junit.jupiter.execution.parallel.enabled=true
    #是否支持方法级别多线程same_thread/concurrent
    junit.jupiter.execution.parallel.mode.default=concurrent
    #是否支持类级别多线程same_thread/concurrent
    junit.jupiter.execution.parallel.mode.classes.default=concurrent
    # the maximum pool size can be configured using a ParallelExecutionConfigurationStrategy
    junit.jupiter.execution.parallel.config.strategy=fixed
    junit.jupiter.execution.parallel.config.fixed.parallelism=5

    3、测试代码

    package com.wechat.testcase;
    
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.MethodOrderer;
    import org.junit.jupiter.api.RepeatedTest;
    import org.junit.jupiter.api.TestMethodOrder;
    import org.junit.jupiter.api.parallel.Execution;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import static org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT;
    
    /**
     * 线程测试
     */
    //@Execution(CONCURRENT)
    @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
    public class Demo_07_1 {
        private static final Logger logger = LoggerFactory.getLogger(Demo_07_1.class);
    
        @DisplayName("线程测试01")
        @RepeatedTest(10)
        @Execution(CONCURRENT)
        void threadTest01() throws InterruptedException {
            Thread.sleep(3000);
            long id = Thread.currentThread().getId();
            logger.info("线程号" + id + "==>装入坚果01 " + "
    ");
        }
    
        @DisplayName("线程测试02")
        @Execution(CONCURRENT)
        @RepeatedTest(10)
        void threadTest02() throws InterruptedException {
            Thread.sleep(3000);
            long id = Thread.currentThread().getId();
            logger.info("线程号" + id + "==>装入坚果02 " + "
    ");
        }
    }

    测试结果:

     4、真实案例(企业微信部门创建接口)---测试接口是否是线程安全以及分布式线程安全

    package com.wechat.testcase;
    
    import com.wechat.apiobject.DepartmentApiObject;
    import com.wechat.apiobject.TokenHelper;
    import io.restassured.response.Response;
    import org.junit.jupiter.api.*;
    import org.junit.jupiter.api.parallel.Execution;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT;
    
    /**
     * 线程测试
     */
    //@Execution(CONCURRENT)
    @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
    public class Demo_07_2 {
        private static final Logger logger = LoggerFactory.getLogger(Demo_07_2.class);
        static String accessToken;
    
        @BeforeAll
        public static void getAccessToken() throws Exception {
            accessToken = TokenHelper.getAccessToken();
            logger.info(accessToken);
        }
    
        @DisplayName("创建部门")
        @RepeatedTest(20)
        @Execution(CONCURRENT)
        void createDepartment() {
            String creatName = "name1234567";
            String creatEnName = "en_name1234567";
    
            Response creatResponse = DepartmentApiObject.createDepartment(creatName, creatEnName, accessToken);
            assertEquals("0", creatResponse.path("errcode").toString());
        }
    }

    测试结果:

     备注:说明企业微信的部门创建接口是做了线程安全和幂等性处理,5个线程同时执行20条相同的部门创建请求,只有1条是成功,19条是失败

    5、真实案例(企业微信部门创建和修改接口)---测试数据库是否安全

    /**
     * projectName: WeChatWorkApiTest
     * fileName: Demo_01.java
     * packageName: com.wechat.testcase
     * date: 2020-07-18 2:49 下午
     */
    package com.wechat.testcase;
    
    import com.wechat.apiobject.DepartmentApiObject;
    import com.wechat.apiobject.TokenHelper;
    import com.wechat.utils.FakeUtils;
    import io.qameta.allure.Description;
    import io.restassured.response.Response;
    import org.junit.jupiter.api.BeforeAll;
    import org.junit.jupiter.api.MethodOrderer;
    import org.junit.jupiter.api.RepeatedTest;
    import org.junit.jupiter.api.TestMethodOrder;
    import org.junit.jupiter.api.parallel.Execution;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT;
    
    /**
     * 优化记录:
     * 1、增加了入参实时获取的逻辑
     * 2、增加了脚本的独立性改造
     * 3、通过添加evnClear方法解决脚本无法重复运行的问题
     * 4、对脚本行了分层,减少了重复代码,减少了很多维护成本
     **/
    @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
    public class Demo_07_03 {
        private static final Logger logger = LoggerFactory.getLogger(Demo_07_03.class);
    
        static String accessToken;
        static String departmentId;
    
        @BeforeAll
        static void getAccessToken() {
            accessToken = TokenHelper.getAccessToken();
        }
    
    
        @Description("创建部门")
        @RepeatedTest(10)
        @Execution(CONCURRENT)
        void creatDepartment() {
            String backentStr = Thread.currentThread().getId() + FakeUtils.getTimeStamp();
            String creatName = "creatName" + backentStr;
            String creatNameEn = "creatNamEn" + backentStr;
    
            Response creatResponse = DepartmentApiObject.createDepartment(creatName, creatNameEn, accessToken);
            departmentId = creatResponse.path("id") != null ? creatResponse.path("id").toString() : null;
            assertEquals("0", creatResponse.path("errcode").toString());
        }
    
        @Description("更新部门")
        @RepeatedTest(10)
        @Execution(CONCURRENT)
        void updateDepartment() {
            String backentStr = Thread.currentThread().getId() + FakeUtils.getTimeStamp();
    
            String creatName = "creatName" + backentStr;
            String creatNameEn = "creatNamEn" + backentStr;
    
            Response creatResponse = DepartmentApiObject.createDepartment(creatName, creatNameEn, accessToken);
            departmentId = creatResponse.path("id") != null ? creatResponse.path("id").toString() : null;
    
            String updateName = "updateName" + backentStr;
            String updateNameEn = "updateNameEn" + backentStr;
    
            Response updateResponse = DepartmentApiObject.updateDepartment(updateName, updateNameEn, departmentId, accessToken);
            assertEquals("0", updateResponse.path("errcode").toString());
    
        }
    
    }

    测试结果:

     备注:20条用例被5个线程同时执行,都没有报错,说明其接口的表索引和程序处理得当

     五、总结

    我们需要扎实的掌握junit5,理论结合实际,才能让我们的产品不出重大bug

    知道、想到、做到、得到
  • 相关阅读:
    【BestCoder #48】
    【一场模拟赛?】
    【普通の随笔】6.30
    【BestCoder #45】
    【BestCoder #44】
    【普通の惨败】GDOI2015卖萌记
    我的新博客
    【BZOJ 2964】Boss单挑战
    【NOI 2015】软件包管理器
    【NOI 2015】程序自动分析
  • 原文地址:https://www.cnblogs.com/Durant0420/p/14994464.html
Copyright © 2011-2022 走看看