单元测试利器 Mockito

简介: 单元测试利器 Mockito

前言

Mockito是当前最流行的单元测试Mock框架。我们可以虚拟出一个外部依赖,降低测试组件之间的耦合度,只注重代码的流程与结果,真正地实现测试目的。

什么是Mockito

Mock的中文译为仿制的,模拟的,虚假的。对于测试框架来说,即构造出一个模拟/虚假的对象,使我们的测试能顺利进行下去。

ito 其实是input to output

Mockito 大致意思就是模拟输入和输出,用一个 虚拟的对象( Mock对象)来创建,以便测试方法。

为什么使用Mock测试

单元测试是为了验证我们的代码运行正确性,我们注重的是代码的流程以及结果的正确与否。

对比真实运行代码,可能其中有一些外部依赖的构建步骤相对麻烦,测试用例显得复杂难懂,会大大增加单元测试的工作。

使用Mock,我们可以虚拟出一个外部依赖,只注重代码的流程与结果,真正地实现测试目的。

使用Mock测试的好处

  1. 可以很简单的虚拟出一个复杂对象(比如虚拟出一个接口的实现类);
  2. 可以使测试用例只注重测试流程与结果;
  3. 减少外部类、系统和依赖给单元测试带来的耦合。
  4. 团队可以并行工作(比如A依赖B,但B并没有开发,此时就可以Mock出一个B

使用Mockito测试示例

C层代码:

@RestController
@RequestMapping("Student")
public class StudentController {
    @Autowired
    StudentService studentService; 
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Student save(@RequestBody Student student) {
        return studentService.save(student); 
    }
}

M层代码:

  • 接口
public interface StudentService {
    Student save(Student student);
}

实现类:

@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    StudentRepository studentRepository;
    @Override
    public Student save(Student student) {
        return studentRepository.save(student);
    }
}

实现类:

@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    StudentRepository studentRepository;
    @Override
    public Student save(Student student) {
        return studentRepository.save(student);
    }
}
以save这个方法为例,进行 C M 层测试

测试C层:

  1. 模拟发送请求

image.png

  1. 测试传入的值是否符合预期

image.png

  1. 测试返回的值是否符合预期

image.png


public class StudentControllerTest {
    @Test
    public void save() throws Exception {
        // 模拟发送请求 
        logger.info("准备输入数据");
        String url = "Student";
        JSONObject studentJsonObject = new JSONObject();
        JSONObject klassJsonObject = new JSONObject();
        studentJsonObject.put("sno", "学号测试");
        studentJsonObject.put("name", "姓名测试");
        klassJsonObject.put("id", -1);
        studentJsonObject.put("klass", klassJsonObject);
        logger.info("发起请求");
        MvcResult mvcResult = this.mockMvc.perform(
                MockMvcRequestBuilders.post(url)
                    .content(studentJsonObject.toString()
                    .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(MockMvcResultMatchers.status().is(201)
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
        // 测试传入的值是否符合预期
        logger.info("新建参数捕获器");
        ArgumentCaptor<Student> studentArgumentCaptor = ArgumentCaptor.forClass(Student.class);
        Mockito.verify(studentService).save(studentArgumentCaptor.capture());
        Student passedStudent = studentArgumentCaptor.getValue();
        logger.info("断言捕获的对与我们前面传入的值的相同");             
        Assertions.assertThat(passedStudent.getSno()).isEqualTo("学号测试");
        Assertions.assertThat(passedStudent.getName()).isEqualTo("姓名测试");
        Assertions.assertThat(passedStudent.getId()).isNull();
        Assertions.assertThat(passedStudent.getKlass().getId()).isEqualTo(-1L);
        // 测试返回的值是否符合预期
        logger.info("准备服务层被调用后的返回数据");
        Student returnStudent = new Student();
        returnStudent.setId(1L);
        returnStudent.setSno("测试返回学号");
        returnStudent.setName("测试返回姓名");
        returnStudent.setKlass(new Klass());
        returnStudent.getKlass().setId(1L);
        Mockito.when(studentService.save(Mockito.any(Student.class))).thenReturn(returnStudent);
        logger.info("获取返回的值并断言此值与我们模拟的返回值相同");
        String stringReturn = mvcResult.getResponse().getContentAsString();
        DocumentContext documentContext = JsonPath.parse(stringReturn);
        LinkedHashMap studentHashMap = documentContext.json();
        Assertions.assertThat(studentHashMap.get("id")).isEqualTo(1);
        Assertions.assertThat(studentHashMap.get("sno")).isEqualTo("测试返回学号");
        Assertions.assertThat(studentHashMap.get("name")).isEqualTo("测试返回姓名");
        LinkedHashMap klassHashMap = (LinkedHashMap) studentHashMap.get("klass");
        Assertions.assertThat(klassHashMap.get("id")).isEqualTo(1);
    }
}

测试M层:

  • M层单元测试相对比较简单,不需要模拟前台的数据,逻辑更加清晰

image.png

public class StudentServiceImplTest {
    @Test
    public void save() {
        logger.info("准备传入的数据");
        Student passStudent = new Student();
        logger.info("调用服务层");
        Student returnStudent = studentService.save(passStudent);
        logger.info("准备返回的数据");  
        Student mockReturnStudent = new Student();
        Mockito.when(studentRepository.save(Mockito.any(Student.class))).thenReturn(mockReturnStudent);
        logger.info("新建参数捕获器");
        ArgumentCaptor<Student> studentArgumentCaptor =ArgumentCaptor.forClass(Student.class);
        Mockito.verify(studentRepository).save(studentArgumentCaptor.capture());
        logger.info("断言获取的数据与传入的相同");
        Assertions.assertThat(studentArgumentCaptor.getValue()).isEqualTo(passStudent);
        logger.info("断言返回的数据与输出的相同");
        Assertions.assertThat(returnStudent).isEqualTo(mockReturnStudent);
    }
}


总结

总感觉当时能搞明白啥意思,但是时间一长自己还是有点懵,还需要捋一下思路才行,所有在此简单记录总结一下。
目录
相关文章
|
2月前
|
XML Java 测试技术
【Java技术专题】「核心技术提升」最流行的Java模拟框架Mockito入门指南(Java单元测试)
【Java技术专题】「核心技术提升」最流行的Java模拟框架Mockito入门指南(Java单元测试)
32 0
|
Java 测试技术 容器
Springboot+mockito进行单元测试心得整体
## SpringBoot应用测试 测试Springboot应用需要依赖一个非常重要的注解@SpringBootTest,这个注解会为测试用例构建Spring容器。@SpringBootTest注解修饰的测试用例默认不会启动web容器,如果需要启动web容器需要设置webEnvironment属性: * MOCK(默认):会启动一个mock的web server,可以配合@AutoConfig
6296 0
|
4月前
|
Java 测试技术 API
【Java技术深入解析】「核心技术提升」最流行的Java模拟框架Mockito入门指南(Java单元测试)
还在使用 Mockito 1.x?看看 Mockito 2 有哪些新功能!Mockito 3 没有引入任何破坏性的 API 变动,但现在需要 Java 8 而不是 Mockito 2 的 Java 6。 Mockito 4 删除了过时的 API。Mockito 5 将默认 mockmaker 改为 mockito-inline,现在需要 Java 11。一次只支持一个主要版本,而且不会向旧版本回传更改内容。
69 0
【Java技术深入解析】「核心技术提升」最流行的Java模拟框架Mockito入门指南(Java单元测试)
|
11月前
|
Java 测试技术 Spring
Mockito + Junit + SpringBoot进行单元测试
Mockito + Junit + SpringBoot进行单元测试
210 0
|
12月前
|
Java 测试技术 数据库
SpringBoot - 单元测试利器Mockito入门
SpringBoot - 单元测试利器Mockito入门
349 0
|
监控 Java 测试技术
spring单元测试之Mockito
Mockito 是一个针对 Java 的单元测试模拟框架,它与 EasyMock 和 jMock 很相似,都是为了简化单元测试过程中测试上下文 ( 或者称之为测试驱动函数以及桩函数 ) 的搭建而开发的工具
|
测试技术 容器 API
JUnit + Mockito 单元测试(二)
JUnit 是单元测试框架。Mockito 与 JUnit 不同,并不是单元测试框架(这方面 JUnit 已经足够好了),它是用于生成模拟对象或者直接点说,就是”假对象“的工具。两者定位不同,所以一般通常的做法就是联合 JUnit + Mockito 来进行测试。
2021 0
|
Java 数据库连接 测试技术
【mockito】单元测试之mockito简单使用
项目使用的是springmvc+mybatis 开发; mock包为 mockito-all;虽然也引用了powermock,但截至目前,还未使用到;如果使用到后续再补相关笔记。
|
Java 测试技术 API
SpringBoot 实战:JUnit5+MockMvc+Mockito 做好单元测试
今天聊聊如何在 SpringBoot 中集成 Junit5、MockMvc、Mocktio。Junit5 是在 Java 栈中应用最广的测试框架,Junit4 一度霸榜。
890 0
SpringBoot 实战:JUnit5+MockMvc+Mockito 做好单元测试
|
Java 测试技术 Maven
Java单元测试之 Mockito
对于程序员是否有必要编写test case,何时编写依然存在很多争议,各种互斥的方法论(SE/AM/XP/TDD),以及不同的开发文化,但是可以确定是编写单元测试用例有助于提高编程能力。
676 0