正经人谁写 Junit 啊!

2021-05-08 14:18:45 浏览数 (1)

前言

开发流程

这也太敏捷了

你的单元测试呢?

测了几个功能?

代码覆盖率多少?

哦,你说这些啊,我从来不写单元测试!

惊!你这单元测试的姿势都不对,就和打王者一样,同样是玩游戏,有人躺着,有人跪着……

来,赶紧过来跟着我看看单元测试!

1 项目分层

一般开发过程中,都是要对项目进行分层的,先来看看阿里巴巴 Java 开发手册中,是如何对项目进行分层的?

Java 开发手册

当然实际工作中不可能是这样的,再来看看我一般使用的分层:

差不多这样吧!

2 单元测试

至于单元测试,一般情况下,是很少写。(除非无奈,一般人都不写吧!)

不会吧!不会吧!还有人写单元测试,单元测试不就是为了代码扫描的时候通过一下嘛?

其实,单元测试是有要求的!

在 IDEA 中 clean install 时,也会执行 maven 的 test 插件,运行一遍所有的 junit。

当然,如果希望执行 test 可以点击

或者执行命令:

忽略掉测试即可。

也有其他的方法忽略测试,比如配置 <skipTests>true</skipTests><maven.test.skip>true</maven.test.skip>

总之,单元测试是会在打包的时候自动执行,也可以忽略。并且单元测试要允许重复执行。

不能说我今天执行成功,第二天执行失败。

具体可以在阿里巴巴 Java 开发手册单元测试章节已经说明很多了。

至此,都是为了说明一个道理,单元测试很重要!

下面来看看单元测试的使用姿势!

3 单元测试的使用

既然对项目进行了分层,那肯定要每一层都要测试到。所以就一起看看我最近学到的单元测试的新知识!

IDEA 快捷创建单元测试

在开始之前,先说下 IDEA 的快捷键,有助于提高开发效率。

  1. ⌥ ⏎ (Option Enter)
  1. ⌘ N

快捷创建 Junit 测试类。

姿势一:Dao 层测试

需要注解:

  • @Transactional
  • @Rollback
  • @Sql

比如呢?我想测试插入用户。

代码语言:javascript复制
@Slf4j
@Rollback
@Transactional
@RunWith(SpringRunner.class)
@SpringBootTest(classes = WebApplication.class)
public class UserMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    @Sql(statements = "delete from user_info")
    public void insertUser() throws CustomException {

        // 创建 userInfo 对象, 都是伪代码!
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId("1000001");
        userInfo.setUserName("liuzhihang");

        userInfoMapper.insertUserInfo(userInfo);

        UserInfo record = userInfoMapper.selectById("1000001");

        Assert.assertNotNull(record);

    }
}
  1. @Sql(statements = "delete from user_info") 注解,保证 junit 执行之前,把表清了;
  2. 先插入再查询,Assert 断言结果是否 OK;
  3. @Rollback@Transactional 保证 junit 执行结束回滚。
姿势二:Service 层测试

需要注解

  • @MockBean
代码语言:javascript复制
@Slf4j
@Rollback
@SpringBootTest(classes = WebApplication.class)
public class UserServiceTest {

    @MockBean
    private UserInfoMapper userInfoMapper;

    @Autowired
    private UserInfoService userInfoService;

    @Test
    public void insertUser() throws CustomException {

        // 创建 userInfo 对象, 都是伪代码!
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId("1000001");
        userInfo.setUserName("liuzhihang");

        Mockito.when(userInfoMapper.selectById("1000001")).thenReturn(userInfo);
        
        UserInfoRespDTO respDTO = userInfoService.queryUserInfo("1000001");

        Assert.assertNotNull(respDTO);

    }
}

意思到了就行,细节不重要。

核心姿势:

  1. @MockBean
  2. Mockito.when().thenReturn();

这样可以在 service 方法中调用到其他组件的某个方法的时候,mock 一个返回数据。比如:

  1. Mock Mapper 层的返回结果;
  2. Mock 远端的返回结果。

Mock 远程调用时,需要使用门面模式把远程 Dubbo 接口或者 Http 接口进行包装,然后 mock 自己的门面即可。

姿势三:Controller 层测试

这个就简单了,直接项目起起来,然后一个 Postman,一切结束。

其实,并不然。

需要注解:

  • @WebMvcTest
  • @MockBean

需要注入对象:

  • MockMvc
代码语言:javascript复制
@WebMvcTest(UserInfoController.class)
public class UserInfoControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserInfoService userInfoService;

    @Test
    public void queryUserInfo() throws CustomException {

        // 创建 userInfo 对象, 都是伪代码!
        UserInfoDTO userInfoDTO = new UserInfoDTO();
        userInfoDTO.setUserId("1000001");
        userInfoDTO.setUserName("liuzhihang");

        Mockito.when(userInfoService.queryUserInfo("1000001")).thenReturn(userInfoDTO);

        mockMvc.perform(post("/user/queryUserInfo")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(JSON.toJSONString(reqVO)))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value("00000"))
                .andReturn()
                .getResponse()
                .getContentAsString();
    }
}

核心姿势:

  1. @MockBean
  2. Mockito.when().thenReturn();
  3. MockMvc
  4. mockMvc.perform……

调用 service 时,mock 一份 service 返回的 DTO,然后使用 mockMvc 对象请求接口并校验返回。

姿势四:使用断言

除了上面介绍的注解之外,还需要注意 Assert 断言的使用。

一般情况下默认的 Assert 就可以满足使用,当然复杂情况的断言可以使用 Mockito 框架提供的断言。

具体姿势,就看看官方文档吧!

4 总结

本文简单介绍了为什么要使用 junit,以及如何使用 junit 对工程的各个分层进行测试。

心动不如行动。

赶紧去试试吧!

- <End /> -

0 人点赞