junit5|并行测试

一、需求背景

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

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

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

二、解决方案

junit5的并行测试

三、前提条件

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

四、具体步骤

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

junit5|并行测试

 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 " + "\n");
    }

    @DisplayName("线程测试02")
    @Execution(CONCURRENT)
    @RepeatedTest(10)
    void threadTest02() throws InterruptedException {
        Thread.sleep(3000);
        long id = Thread.currentThread().getId();
        logger.info("线程号" + id + "==>装入坚果02 " + "\n");
    }
}

测试结果:

junit5|并行测试

 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());
    }
}

测试结果:

junit5|并行测试

 备注:说明企业微信的部门创建接口是做了线程安全和幂等性处理,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());

    }

}

测试结果:

junit5|并行测试

 

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

 五、总结

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

 

junit5|并行测试

上一篇:Vue中watch与computed的区别


下一篇:DM8_DSC集群部署