一、背景
Mockito 是一个很好用的模拟框架。它让您可以使用干净简单的 API 编写漂亮的测试。Mockito 的可读性非常好,不会让你感到迷惑,产生的验证错误也很明确。
二、应用场景
日常工作中很多时候我们都需要同事间的相互配合协作完成某些功能,所以我们经常会遇到服务或者应用内不同模块之间要互相依赖的场景。
比如下面的场景,serviceA 中的 methodA() 方式依赖 serviceB 中的 methodB() 方法返回操作的结果。那如果我们要对自己的methodA() 方法进行编写单元测试,还需要等其他同事的methodB() 方法开发完成才行。
那有没有什么办法我们可以跳过或者说模拟方法 B 的输出呢?这就引出了我们今天的主角 Mockito,一个优秀的 Mock 测试框架。
1、提升代码质量
2、提升测试自动化水平
三、实践
Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
# 或
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>2.0.2-beta</version>
</dependency>
从以下八个点实践如何使用
四、代码示例
package com.mockito;
import com.mockito.service.Car;
import com.mockito.service.Task;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.IOException;
import static org.mockito.Mockito.*;
/**
* {@Code demoInjectTest}
*
* @Author zhutaotao
* @Date 2023/2/24 14:53
*/
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class DemoInjectTest {
@InjectMocks
private Task taskService;
@Mock
private Car car;
@Before
public void before(){
MockitoAnnotations.openMocks(this);
}
/**
* mock一个对象
* @throws IOException
*/
@Test
public void mockBeanTest() throws IOException {
taskService.doSomething();
verify(taskService).doSomething();
System.out.println("返回值:"+taskService.doSomething());
}
/**
* mock内部成员变量
* @throws IOException
*/
@Test
public void mockInjectTest() throws IOException {
doReturn("new RuntimeException()").when(car).drive();
System.out.println(taskService.doSomething());
}
}
package com.mockito;
import com.mockito.service.Card;
import com.mockito.service.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.IOException;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
/**
* {@Code demoTest}
*
* @Author zhutaotao
* @Date 2023/2/24 11:07
*/
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class DemoTest {
/**
* mock一个对象
* @throws IOException
*/
@Test
public void mockBeanTest() throws IOException {
Task taskService = mock(Task.class);
taskService.doSomething();
verify(taskService).doSomething();
System.out.println("返回值:"+taskService.doSomething());
}
/**
* 测试桩
*/
@Test
public void mockStubTest(){
Task taskService = mock(Task.class);
doReturn("1").when(taskService).doSomething();
taskService.doSomething();
verify(taskService).doSomething();
System.out.println("返回值:"+taskService.doSomething());
}
/**
* 参数匹配器
*/
@Test
public void mockParameterTest(){
Task taskService = mock(Task.class);
when(taskService.doSomething(eq("error"))).thenReturn("str");
taskService.doSomething("str");
verify(taskService).doSomething(anyString());
System.out.println("返回值:"+taskService.doSomething("error"));
}
/**
* 调用次数验证
*/
@Test
public void mockAtLeastTest(){
Task taskService = mock(Task.class);
when(taskService.doSomething(eq("error"))).thenReturn("str");
taskService.doSomething("str");
// 其它:only() never()
verify(taskService,atLeast(3)).doSomething(anyString());
System.out.println("返回值:"+taskService.doSomething("error"));
}
/**
* 无返回打桩
*/
@Test
public void mockVoidTest(){
Task taskService = mock(Task.class);
doThrow(new RuntimeException()).when(taskService).voidReturn();
taskService.voidReturn();
}
/**
* 顺序执行
*/
@Test
public void mockOrderTest(){
List<String> taskService = mock(List.class);
taskService.add("first");
taskService.add("second");
// 顺序
InOrder inOrder = inOrder(taskService);
inOrder.verify(taskService).add("second");
inOrder.verify(taskService).add("first");
}
/**
* 捕获参数
*/
@Test
public void mockCaptureArgsTest(){
Card card = mock(Card.class);
card.getMoney("123456");
//参数捕获
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
verify(card).getMoney(argumentCaptor.capture());
assertEquals("123456",argumentCaptor.getValue());
}
}