springboot+idea+junit5整合

1、idea整合junit5之前,先安装配置junit插件:https://blog.csdn.net/nicolas12/article/details/81223938
2、添加pom依赖:


        
            org.junit.platform
            junit-platform-launcher
            1.3.2
            test
        
        
        
            org.junit.jupiter
            junit-jupiter-engine
            5.3.2
            test
        

        
            org.junit.vintage
            junit-vintage-engine
            5.3.2
            test
        

        
            org.junit.jupiter
            junit-jupiter-params
            5.3.2
            test
        

        
            org.junit.jupiter
            junit-jupiter-api
            5.3.2
            test
        

3、命名:工具生成的名字一般是在测试的方法名前面加test及首字母大写,比如addApps -> testAddApps
但是一般测试不同的条件场景情况较多,所以一般建议不同的入参命名规则为:前面的名字不变,后面加入参的条件,举例为testAddAppsWhenChannelIdIsZero和testAddAppsWhenChannelNotExist就是不同的情况用When连接不同的条件。

4、几种常用的注解(导org.junit.jupiter包)
A、@Test 表示方法是一种测试方法
B、@Disabled 表示会跳过此测试方法
C、@DisplayName 为测试类或者测试方法自定义一个名称,举例

    @DisplayName("test Disabled")
    @Disabled
    @Test
    void testDisabled(){
        log.info("test Disabled");
    }

D、@BeforeEach 表示方法在每个测试方法运行前都会运行
E、@AfterEach 表示方法在每个测试方法运行之后都会运行
F、@BeforeAll 表示方法在所有测试方法之前运行(类级别方法,必须位静态方法)
G、@AfterAll 表示方法在所有测试方法之后运行 (类级别方法,必须位静态方法)

    @BeforeAll
    public static void BeforeEach() throws Exception {
        //在所有测试方法运行前运行
        log.info("Run before all test methods run");
    }

    @BeforeEach
    public void before() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

H、@RepeatedTest(重复测试,测试高并发用)
I、@EnabledOnOs(在什么环境执行),如 @EnabledOnOs({ LINUX, MAC }),也可以自定义举例:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@EnabledOnOs(MAC)
@interface TestOnMac {
}

@TestOnMac
void testOnMac() {
    // ...
}

J、@EnabledOnJre(基于哪个版本的jre执行)如 @EnabledOnJre({ JAVA_9, JAVA_10 })
5、断言
A、assertEquals 断言预期值和实际值相等(参数可以是int double string等等)
B、assertFalse 断言条件为假
C、assertNotNull 断言不为空
D、assertFalse 断言条件为真 举例:

//参数为int
assertEquals(Math.round(Double.valueOf(gson.fromJson(result, Map.class).get("code").toString())),0);
//参数位字符串
assertEquals(result,"");
//参数为boolean
assertTrue(Math.round(Double.valueOf(gson.fromJson(result, Map.class).get("code").toString()))==0);

E、assumeTrue 假设为true时才会执行,如果为false,那么将会直接停止执行 举例:

 assumeTrue(!gson.fromJson(result, Map.class).get("msg").toString().contains("channelId must more than or equal to 1"));
 assumeTrue(!gson.fromJson(result, Map.class).get("msg").toString().contains("name must hava a value"));
 assumeTrue(!gson.fromJson(result, Map.class).get("msg").toString().contains("appKey must hava a value"));

6、参数化测试
@ParameterizedTest(替代@Test)
@CsvSource(多个参数的多组测试)
@ValueSource(单个参数的多组测试)
@EnumSource 其实跟@ValueSource差不多,只不过可以复用枚举类。举例:

public enum ActivityLimitEnum {
  LIMIT(1,"封顶"),
  UNLIMIT(0,"上不封顶");
}

@ParameterizedTest
@EnumSource(ActivityLimitEnum.class)
@DisplayName("封顶和不封顶")
void test(ActivityLimitEnum activityLimitEnum) {
  if (ActivityLimitEnum.LIMIT.equals(activityLimitEnum)) {
    assertFalse(false);
  } 
  else if (ActivityLimitEnum.UNLIMIT.equals(activityLimitEnum)) {
    assertTrue(true);
  }
}

@MethodSource(将一个方法的返回值作为测试方法的入参,引用的方法返回值必须是Stream, Iterator 或者Iterable) 如:

@ParameterizedTest
    @MethodSource("stringGenerator")
    public void test(String str){
        System.out.println(str);
    }

    static Stream stringGenerator(){
        return Stream.of("hello", "world", "let's", "test");
    }

7、MockMvc使用(模拟controller请求接收)

A、GET请求

     /**
     * Method: findAppListByChannelId(Integer channelId)
     */
    @DisplayName("query apps information by channelId")
    @ParameterizedTest
    @ValueSource(strings = {"1", "2", "3"})
    public void testFindAppListByChannelId(String channelId) throws Exception {
        String result = mockMvc.perform(
                get("/v1/appver/apps/list-by-channel")    //请求的url,请求的方法是get
                        .param("channelId", channelId)         //添加参数
                        .contentType(MediaType.APPLICATION_JSON_UTF8)
        ).andExpect(status().isOk())    //返回的状态是200
                .andReturn().getResponse().getContentAsString();   //将相应的数据转换为字符串

        assertTrue(Math.round(Double.valueOf(gson.fromJson(result, Map.class).get("code").toString()))==0);
    }

注意:get请求的参数全部写String类型,由param方法自动装配成需要的类型。

B、POST请求

/**
     * Method: addApps(AppsBo appsBo)
     */
    @DisplayName("add apps information success")
    @ParameterizedTest
    @CsvSource({"app1, key1,1", "app2, key2,1"})
    public void testAddAppsSuccess(String name, String appKey, int channdlId) throws Exception {
        log.info("test testAddAppsSuccess end");
        Date date = new Date();
        AppsBo appsBo = new AppsBo();
        appsBo.setName(name);
        appsBo.setChannelId(channdlId);
        appsBo.setAppKey(appKey);
        String requestBody = gson.toJson(appsBo);
        Map map = gson.fromJson(requestBody, Map.class);
        map.put("createTime", date.getTime());
        String newRequestBody = gson.toJson(map);
        String result = mockMvc.perform(MockMvcRequestBuilders
                .post("/v1/appver/apps/add")
                .content(newRequestBody)
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andReturn()
                .getResponse().getContentAsString();|-----|-----|-----| 
        //assumeTrue的参数为true时才继续往下走,否则就停止到此
        assumeTrue(!gson.fromJson(result, Map.class).get("msg").toString().contains("The channel not exist"));
        assertEquals(Math.round(Double.valueOf(gson.fromJson(result, Map.class).get("code").toString())),0);
        log.info("test testAddAppsSuccess finished");
    }

几个方法的简单说明:

方法名 作用 举例
param 请求的参数设置方法 .param(“channelId”, channelId)
post 请求方法 .post("/v1/appver/apps/add")
content 请求参数 .content(newRequestBody)
contentType 参数类型 .contentType(MediaType.APPLICATION_JSON)
accept 接收返回值类型 .accept(MediaType.APPLICATION_JSON)
andExpect 添加执行完成后的断言 .andExpect(status().isOk())
andReturn 表示执行完成后返回相应的结果 .andReturn()

最后注意:因为测试不能影响数据库的数据,所以测试类上都要加事务回滚 如下:

@Slf4j
@SpringBootTest
@ExtendWith(SpringExtension.class)
@Rollback
@Transactional
public class AppverAppsControllerTest {

测试用例得出的某些问题:
1、添加数据时,要考虑重名判断,用assumeTrue判断返回的校验提示语。
2、修改数据时,要考虑参数Id是否在表中存在,不存时候mybatis-plus会将其作为插入数据处理,插入数据时要保证某些数据不能为空,所以建议加个自定义校验,用assumeTrue判断返回的校验提示语,专门处理junit或者postMan请求的情况。也要和添加数据一样考虑各种校验问题。

你可能感兴趣的:(springboot)