手把手教你Mockito的使用_mockito依赖坐标
一、前期准备~
1、准备工作
- 
 - 
 - 
org.mockito - 
mockito-core - 
2.7.19 - 
test - 
 - 
 - 
 - 
junit - 
junit - 
4.12 - 
test - 
 
2、入门知识
1)Mockito:简单轻量级的做mocking测试的框架;
2)mock对象:在调试期间用来作为真实对象的替代品;
3)mock测试:在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试;
4)stub:打桩,就是为mock对象的方法指定返回值(可抛出异常);
5)verify:行为验证,验证指定方法调用情况(是否被调用,调用次数等);
3、五分钟入门Demo
- 
@Test - 
public void test0() { - 
//1、创建mock对象(模拟依赖的对象) - 
final List mock = Mockito.mock(List.class); - 
//2、使用mock对象(mock对象会对接口或类的方法给出默认实现) - 
System.out.println(\"mock.add result => \" + mock.add(\"first\")); //false - 
System.out.println(\"mock.size result => \" + mock.size()); //0 - 
//3、打桩操作(状态测试:设置该对象指定方法被调用时的返回值) - 
Mockito.when(mock.get(0)).thenReturn(\"second\"); - 
Mockito.doReturn(66).when(mock).size(); - 
//3、使用mock对象的stub(测试打桩结果) - 
System.out.println(\"mock.get result => \" + mock.get(0)); //second - 
System.out.println(\"mock.size result => \" + mock.size()); //66 - 
//4、验证交互 verification(行为测试:验证方法调用情况) - 
Mockito.verify(mock).get(Mockito.anyInt()); - 
Mockito.verify(mock, Mockito.times(2)).size(); - 
//5、验证返回的结果(这是JUnit的功能) - 
assertEquals(\"second\", mock.get(0)); - 
assertEquals(66, mock.size()); - 
} 
二、让我们开始学习吧!
1、行为验证
一旦mock对象被创建了,mock对象会记住所有的交互,然后你就可以选择性的验证你感兴趣的交互,验证不通过则抛出异常。
- 
@Test - 
public void test1() { - 
final List mockList = Mockito.mock(List.class); - 
mockList.add(\"mock1\"); - 
mockList.get(0); - 
mockList.size(); - 
mockList.clear(); - 
// 验证方法被使用(默认1次) - 
Mockito.verify(mockList).add(\"mock1\"); - 
// 验证方法被使用1次 - 
Mockito.verify(mockList, Mockito.times(1)).get(0); - 
// 验证方法至少被使用1次 - 
Mockito.verify(mockList, Mockito.atLeast(1)).size(); - 
// 验证方法没有被使用 - 
Mockito.verify(mockList, Mockito.never()).contains(\"mock2\"); - 
// 验证方法至多被使用5次 - 
Mockito.verify(mockList, Mockito.atMost(5)).clear(); - 
// 指定方法调用超时时间 - 
Mockito.verify(mockList, timeout(100)).get(0); - 
// 指定时间内需要完成的次数 - 
Mockito.verify(mockList, timeout(200).atLeastOnce()).size(); - 
} 
2、如何做一些测试桩stub
默认情况下,所有的函数都有返回值。mock函数默认返回的是null,一个空的集合或者一个被对象类型包装的内置类型,例如0、false对应的对象类型为Integer、Boolean;
一旦测试桩函数被调用,该函数将会一致返回固定的值;
对于 static 和 final 方法, Mockito 无法对其 when(…).thenReturn(…) 操作。
- 
@Test - 
public void test2() { - 
//静态导入,减少代码量:import static org.mockito.Mockito.*; - 
final ArrayList mockList = mock(ArrayList.class); - 
// 设置方法调用返回值 - 
when(mockList.add(\"test2\")).thenReturn(true); - 
doReturn(true).when(mockList).add(\"test2\"); - 
System.out.println(mockList.add(\"test2\")); //true - 
// 设置方法调用抛出异常 - 
when(mockList.get(0)).thenThrow(new RuntimeException()); - 
doThrow(new RuntimeException()).when(mockList).get(0); - 
System.out.println(mockList.get(0)); //throw RuntimeException - 
// 无返回方法打桩 - 
doNothing().when(mockList).clear(); - 
// 为回调做测试桩(对方法返回进行拦截处理) - 
final Answer answer = new Answer() { - 
@Override - 
public String answer(InvocationOnMock invocationOnMock) throws Throwable { - 
final List mock = (List) invocationOnMock.getMock(); - 
return \"mock.size result => \" + mock.size(); - 
} - 
}; - 
when(mockList.get(1)).thenAnswer(answer); - 
doAnswer(answer).when(mockList).get(1); - 
System.out.println(mockList.get(1)); //mock.size result => 0 - 
// 对同一方法多次打桩,以最后一次为准 - 
when(mockList.get(2)).thenReturn(\"test2_1\"); - 
when(mockList.get(2)).thenReturn(\"test2_2\"); - 
System.out.println(mockList.get(2)); //test2_2 - 
System.out.println(mockList.get(2)); //test2_2 - 
// 设置多次调用同类型结果 - 
when(mockList.get(3)).thenReturn(\"test2_1\", \"test2_2\"); - 
when(mockList.get(3)).thenReturn(\"test2_1\").thenReturn(\"test2_2\"); - 
System.out.println(mockList.get(3)); //test2_1 - 
System.out.println(mockList.get(3)); //test2_2 - 
// 为连续调用做测试桩(为同一个函数调用的不同的返回值或异常做测试桩) - 
when(mockList.get(4)).thenReturn(\"test2\").thenThrow(new RuntimeException()); - 
doReturn(\"test2\").doThrow(new RuntimeException()).when(mockList).get(4); - 
System.out.println(mockList.get(4)); //test2 - 
System.out.println(mockList.get(4)); //throw RuntimeException - 
// 无打桩方法,返回默认值 - 
System.out.println(mockList.get(99)); //null - 
} 
3、参数匹配器
参数匹配器使验证和测试桩变得更灵活;
为了合理的使用复杂的参数匹配,使用equals()与anyX() 的匹配器会使得测试代码更简洁、简单。有时,会迫使你重构代码以使用equals()匹配或者实现equals()函数来帮助你进行测试;
如果你使用参数匹配器,所有参数都必须由匹配器提供;
支持自定义参数匹配器;
- 
@Test - 
public void test3() { - 
final Map mockMap = mock(Map.class); - 
// 正常打桩测试 - 
when(mockMap.get(\"key\")).thenReturn(\"value1\"); - 
System.out.println(mockMap.get(\"key\")); //value1 - 
// 为灵活起见,可使用参数匹配器 - 
when(mockMap.get(anyString())).thenReturn(\"value2\"); - 
System.out.println(mockMap.get(anyString())); //value2 - 
System.out.println(mockMap.get(\"test_key\")); //value2 - 
System.out.println(mockMap.get(0)); //null - 
// 多个入参时,要么都使用参数匹配器,要么都不使用,否则会异常 - 
when(mockMap.put(anyString(), anyInt())).thenReturn(\"value3\"); - 
System.out.println(mockMap.put(\"key3\", 3)); //value3 - 
System.out.println(mockMap.put(anyString(), anyInt())); //value3 - 
System.out.println(mockMap.put(\"key3\", anyInt())); //异常 - 
// 行为验证时,也支持使用参数匹配器 - 
verify(mockMap, atLeastOnce()).get(anyString()); - 
verify(mockMap).put(anyString(), eq(3)); - 
// 自定义参数匹配器 - 
final ArgumentMatcher myArgumentMatcher = new ArgumentMatcher() { - 
@Override - 
public boolean matches(ArgumentTestRequest request) { - 
return \"name\".equals(request.getName()) || \"value\".equals(request.getValue()); - 
} - 
}; - 
// 自定义参数匹配器使用 - 
final ArgumentTestService mock = mock(ArgumentTestService.class); - 
when(mock.argumentTestMethod(argThat(myArgumentMatcher))).thenReturn(\"success\"); - 
doReturn(\"success\").when(mock).argumentTestMethod(argThat(myArgumentMatcher)); - 
System.out.println(mock.argumentTestMethod(new ArgumentTestRequest(\"name\", \"value\"))); // success - 
System.out.println(mock.argumentTestMethod(new ArgumentTestRequest())); //null - 
} 
4、执行顺序验证
验证执行顺序是非常灵活的-你不需要一个一个的验证所有交互,只需要验证你感兴趣的对象即可;
你可以仅通过那些需要验证顺序的mock对象来创建InOrder对象;
- 
@Test - 
public void test4() { - 
// 验证同一个对象多个方法的执行顺序 - 
final List mockList = mock(List.class); - 
mockList.add(\"first\"); - 
mockList.add(\"second\"); - 
final InOrder inOrder = inOrder(mockList); - 
inOrder.verify(mockList).add(\"first\"); - 
inOrder.verify(mockList).add(\"second\"); - 
// 验证多个对象多个方法的执行顺序 - 
final List mockList1 = mock(List.class); - 
final List mockList2 = mock(List.class); - 
mockList1.get(0); - 
mockList1.get(1); - 
mockList2.get(0); - 
mockList1.get(2); - 
mockList2.get(1); - 
final InOrder inOrder1 = inOrder(mockList1, mockList2); - 
inOrder1.verify(mockList1).get(0); - 
inOrder1.verify(mockList1).get(2); - 
inOrder1.verify(mockList2).get(1); - 
} 
5、确保交互(interaction)操作不会执行在mock对象上
一些用户可能会在频繁地使用verifyNoMoreInteractions(),甚至在每个测试函数中都用。但是verifyNoMoreInteractions()并不建议在每个测试函数中都使用;
verifyNoMoreInteractions()在交互测试套件中只是一个便利的验证,它的作用是当你需要验证是否存在冗余调用时;
- 
@Test - 
public void test5() { - 
// 验证某个交互是否从未被执行 - 
final List mock = mock(List.class); - 
mock.add(\"first\"); - 
verify(mock, never()).add(\"test5\"); //通过 - 
verify(mock, never()).add(\"first\"); //异常 - 
// 验证mock对象没有交互过 - 
final List mock1 = mock(List.class); - 
final List mock2 = mock(List.class); - 
verifyZeroInteractions(mock1); //通过 - 
verifyNoMoreInteractions(mock1, mock2); //通过 - 
verifyZeroInteractions(mock, mock2); //异常 - 
// 注意:可能只想验证前面的逻辑,但是加上最后一行,会导致出现异常。建议使用方法层面的验证,如:never(); - 
// 在验证是否有冗余调用的时候,可使用此种方式。如下: - 
final List mockList = mock(List.class); - 
mockList.add(\"one\"); - 
mockList.add(\"two\"); - 
verify(mockList).add(\"one\"); // 通过 - 
verify(mockList, never()).get(0); //通过 - 
verifyZeroInteractions(mockList); //异常 - 
} 
6、使用注解简化mock对象创建
注意!下面这句代码需要在运行测试函数之前被调用,一般放到测试类的基类或者test runner中:
MockitoAnnotations.initMocks(this);
也可以使用内置的runner: MockitoJUnitRunner 或者一个rule : MockitoRule;
- 
// 代替 mock(ArgumentTestService.class) 创建mock对象; - 
@Mock - 
private ArgumentTestService argumentTestService; - 
// 若改注解修饰的对象有成员变量,@Mock定义的mock对象会被自动注入; - 
@InjectMocks - 
private MockitoAnnotationServiceImpl mockitoAnnotationService; - 
@Test - 
public void test6() { - 
// 注意!下面这句代码需要在运行测试函数之前被调用,一般放到测试类的基类或者test runner中; - 
MockitoAnnotations.initMocks(this); - 
when(argumentTestService.argumentTestMethod(new ArgumentTestRequest())).thenReturn(\"success\"); - 
System.out.println(argumentTestService.argumentTestMethod(new ArgumentTestRequest())); //success - 
System.out.println(mockitoAnnotationService.mockitoAnnotationTestMethod()); //null - 
} 
7、监控真实对象(部分mock)
可以为真实对象创建一个监控(spy)对象。当你使用这个spy对象时真实的对象也会也调用,除非它的函数被stub了;
尽量少使用spy对象,使用时也需要小心形式,例如spy对象可以用来处理遗留代码;
stub语法中同样提供了部分mock的方法,可以调用真实的方法;
完全mock:
上文讲的内容是完全mock,即创建的mock对象与真实对象无关,mock对象的方法默认都是基本的实现,返回基本类型。可基于接口、实现类创建mock对象。
部分mock:
所谓部分mock,即创建的mock对象时基于真实对象的,mock对象的方法都是默认使用真实对象的方法,除非stub之后,才会以stub为准。基于实现类创建mock对象,否则在没有stub的情况下,调用真实方法时,会出现异常。
注意点:
Mockito并不会为真实对象代理函数调用,实际上它会拷贝真实对象。因此如果你保留了真实对象并且与之交互,不要期望从监控对象得到正确的结果。 当你在监控对象上调用一个没有被stub的函数时并不会调用真实对象的对应函数,你不会在真实对象上看到任何效果
- 
@Test - 
public void test7() { - 
// stub部分mock(stub中使用真实调用)。注意:需要mock实现类,否则会有异常 - 
final StubTestService stubTestService = mock(StubTestServiceImpl.class); - 
when(stubTestService.stubTestMethodA(\"paramA\")).thenCallRealMethod(); - 
doCallRealMethod().when(stubTestService).stubTestMethodB(); - 
System.out.println(stubTestService.stubTestMethodA(\"paramA\")); //stubTestMethodA is called, param = paramA - 
System.out.println(stubTestService.stubTestMethodB()); //stubTestMethodB is called - 
System.out.println(stubTestService.stubTestMethodC()); //null - 
// spy部分mock - 
final LinkedList linkedList = new LinkedList(); - 
final LinkedList spy = spy(linkedList); - 
spy.add(\"one\"); - 
spy.add(\"two\"); - 
doReturn(100).when(spy).size(); - 
when(spy.get(0)).thenReturn(\"one_test\"); - 
System.out.println(spy.size()); //100 - 
System.out.println(spy.get(0)); //one_test - 
System.out.println(spy.get(1)); //two - 
// spy可以类比AOP。在spy中,由于默认是调用真实方法,所以第二种写法不等价于第一种写法,不推荐这种写法。 - 
doReturn(\"two_test\").when(spy).get(2); - 
when(spy.get(2)).thenReturn(\"two_test\"); //异常 java.lang.IndexOutOfBoundsException: Index: 2, Size: 2 - 
System.out.println(spy.get(2)); //two_test - 
// spy对象只是真实对象的复制,真实对象的改变不会影响spy对象 - 
final List arrayList = new ArrayList(); - 
final List spy1 = spy(arrayList); - 
spy1.add(0, \"one\"); - 
System.out.println(spy1.get(0)); //one - 
arrayList.add(0, \"list1\"); - 
System.out.println(arrayList.get(0)); //list1 - 
System.out.println(spy1.get(0)); //one - 
// 若对某个方法stub之后,又想调用真实的方法,可以使用reset(spy) - 
final ArrayList arrayList1 = new ArrayList(); - 
final ArrayList spy2 = spy(arrayList1); - 
doReturn(100).when(spy2).size(); - 
System.out.println(spy2.size()); //100 - 
reset(spy2); - 
System.out.println(spy2.size()); //0 - 
} 
8、@Mock 和 @Spy的使用
@Mock 等价于 Mockito.mock(Object.class);
@Spy 等价于 Mockito.spy(obj);
- 
区分是mock对象还是spy对象: - 
Mockito.mockingDetails(someObject).isMock(); - 
Mockito.mockingDetails(someObject).isSpy(); - 
@Mock - 
private StubTestService stubTestService; - 
@Spy - 
private StubTestServiceImpl stubTestServiceImpl; - 
@Spy - 
private StubTestService stubTestServiceImpl1 = new StubTestServiceImpl(); - 
@Test - 
public void test8() { - 
MockitoAnnotations.initMocks(this); - 
// mock对象返回默认 - 
System.out.println(stubTestService.stubTestMethodB()); //null - 
// spy对象调用真实方法 - 
System.out.println(stubTestServiceImpl.stubTestMethodC()); //stubTestMethodC is called - 
System.out.println(stubTestServiceImpl1.stubTestMethodA(\"spy\")); //stubTestMethodA is called, param = spy - 
// 区分是mock对象还是spy对象 - 
System.out.println(mockingDetails(stubTestService).isMock()); //true - 
System.out.println(mockingDetails(stubTestService).isSpy()); //false - 
System.out.println(mockingDetails(stubTestServiceImpl).isSpy()); //true - 
} 
9、ArgumentCaptor(参数捕获器)捕获方法参数进行验证。(可代替参数匹配器使用)
在某些场景中,不光要对方法的返回值和调用进行验证,同时需要验证一系列交互后所传入方法的参数。那么我们可以用参数捕获器来捕获传入方法的参数进行验证,看它是否符合我们的要求。
ArgumentCaptor介绍
通过ArgumentCaptor对象的forClass(Class
ArgumentCaptor的Api
argument.capture() 捕获方法参数
argument.getValue() 获取方法参数值,如果方法进行了多次调用,它将返回最后一个参数值
argument.getAllValues() 方法进行多次调用后,返回多个参数值
- 
@Test - 
public void test9() { - 
List mock = mock(List.class); - 
List mock1 = mock(List.class); - 
mock.add(\"John\"); - 
mock1.add(\"Brian\"); - 
mock1.add(\"Jim\"); - 
// 获取方法参数 - 
ArgumentCaptor argument = ArgumentCaptor.forClass(String.class); - 
verify(mock).add(argument.capture()); - 
System.out.println(argument.getValue()); //John - 
// 多次调用获取最后一次 - 
ArgumentCaptor argument1 = ArgumentCaptor.forClass(String.class); - 
verify(mock1, times(2)).add(argument1.capture()); - 
System.out.println(argument1.getValue()); //Jim - 
// 获取所有调用参数 - 
System.out.println(argument1.getAllValues()); //[Brian, Jim] - 
} 
10、简化 ArgumentCaptor 的创建
- 
@Mock - 
private List captorList; - 
@Captor - 
private ArgumentCaptor argumentCaptor; - 
@Test - 
public void test10() { - 
MockitoAnnotations.initMocks(this); - 
captorList.add(\"cap1\"); - 
captorList.add(\"cap2\"); - 
System.out.println(captorList.size()); - 
verify(captorList, atLeastOnce()).add(argumentCaptor.capture()); - 
System.out.println(argumentCaptor.getAllValues()); - 
} 
11、高级特性:自定义验证失败信息
- 
@Test - 
public void test11() { - 
final ArrayList arrayList = mock(ArrayList.class); - 
arrayList.add(\"one\"); - 
arrayList.add(\"two\"); - 
verify(arrayList, description(\"size()没有调用\")).size(); - 
// org.mockito.exceptions.base.MockitoAssertionError: size()没有调用 - 
verify(arrayList, timeout(200).times(3).description(\"验证失败\")).add(anyString()); - 
//org.mockito.exceptions.base.MockitoAssertionError: 验证失败 - 
} 
12、高级特性:修改没有测试桩的调用的默认返回值
可以指定策略来创建mock对象的返回值。这是一个高级特性,通常来说,你不需要写这样的测试;
它对于遗留系统来说是很有用处的。当你不需要为函数调用打桩时你可以指定一个默认的answer;
- 
@Test - 
public void test12(){ - 
// 创建mock对象、使用默认返回 - 
final ArrayList mockList = mock(ArrayList.class); - 
System.out.println(mockList.get(0)); //null - 
// 这个实现首先尝试全局配置,如果没有全局配置就会使用默认的回答,它返回0,空集合,null,等等。 - 
// 参考返回配置:ReturnsEmptyValues - 
mock(ArrayList.class, Answers.RETURNS_DEFAULTS); - 
// ReturnsSmartNulls首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回SmartNull。 - 
// 如果最终返回对象,那么会简单返回null。一般用在处理遗留代码。 - 
// 参考返回配置:ReturnsMoreEmptyValues - 
mock(ArrayList.class, Answers.RETURNS_SMART_NULLS); - 
// 未stub的方法,会调用真实方法。 - 
// 注1:存根部分模拟使用时(mock.getSomething ()) .thenReturn (fakeValue)语法将调用的方法。对于部分模拟推荐使用doReturn语法。 - 
// 注2:如果模拟是序列化反序列化,那么这个Answer将无法理解泛型的元数据。 - 
mock(ArrayList.class, Answers.CALLS_REAL_METHODS); - 
// 深度stub,用于嵌套对象的mock。参考:https://www.cnblogs.com/Ming8006/p/6297333.html - 
mock(ArrayList.class, Answers.RETURNS_DEEP_STUBS); - 
// ReturnsMocks首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回mock。 - 
// 如果返回类型不能mocked(例如是final)然后返回null。 - 
mock(ArrayList.class, Answers.RETURNS_MOCKS); - 
// mock对象的方法调用后,可以返回自己(类似builder模式) - 
mock(ArrayList.class, Answers.RETURNS_SELF); - 
// 自定义返回 - 
final Answer answer = new Answer() { - 
@Override - 
public String answer(InvocationOnMock invocation) throws Throwable { - 
return \"test_answer\"; - 
} - 
}; - 
final ArrayList mockList1 = mock(ArrayList.class, answer); - 
System.out.println(mockList1.get(0)); //test_answer - 
} 
三、学习了这么多,牛刀小试一下!
测试实体类
- 
@Data - 
public class User { - 
/** - 
* 姓名,登录密码 - 
*/ 
持久层DAO
- 
public interface UserDao { - 
/** - 
* 根据name查找user - 
* @param name - 
* @return - 
*/ - 
User getUserByName(String name); - 
/** - 
* 保存user - 
* @param user - 
* @return - 
*/ - 
Integer saveUser(User user); - 
} 
业务层Service接口
- 
public interface UserService { - 
/** - 
* 根据name查找user - 
* @param name - 
* @return - 
*/ - 
User getUserByName(String name); - 
/** - 
* 保存user - 
* @param user - 
* @return - 
*/ - 
Integer saveUser(User user); - 
} 
业务层Serive实现类
- 
@Service - 
public class UserServiceImpl implements UserService { - 
//userDao - 
@Autowired - 
private UserDao userDao; - 
/** - 
* 根据name查找user - 
* @param name - 
* @return - 
*/ - 
@Override - 
public User getUserByName(String name) { - 
try { - 
return userDao.getUserByName(name); - 
} catch (Exception e) { - 
throw new RuntimeException(\"查询user异常\"); - 
} - 
} - 
/** - 
* 保存user - 
* @param user - 
* @return - 
*/ - 
@Override - 
public Integer saveUser(User user) { - 
if (userDao.getUserByName(user.getName()) != null) { - 
throw new RuntimeException(\"用户名已存在\"); - 
} - 
try { - 
return userDao.saveUser(user); - 
} catch (Exception e) { - 
throw new RuntimeException(\"保存用户异常\"); - 
} - 
} - 
} 
现在我们的Service写好了,想要单元测试一下,但是Dao是其他人开发的,目前还没有写好,那我们如何测试呢?
- 
public class UserServiceTest { - 
/** - 
* Mock测试:根据name查询user - 
*/ - 
@Test - 
public void getUserByNameTest() { - 
// mock对象 - 
final UserDao userDao = mock(UserDao.class); - 
final UserServiceImpl userService = new UserServiceImpl(); - 
userService.setUserDao(userDao); - 
// stub调用 - 
final User user = new User(); - 
user.setName(\"admin\"); - 
user.setPassword(\"pass\"); - 
when(userDao.getUserByName(\"admin\")).thenReturn(user); - 
// 执行待测试方法 - 
final User user1 = userService.getUserByName(\"admin\"); - 
System.out.println(\"查询结果:\" + JacksonUtil.obj2json(user1)); //查询结果:{\"name\":\"admin\",\"password\":\"pass\"} - 
// 验证mock对象交互 - 
verify(userDao).getUserByName(anyString()); - 
// 验证查询结果 - 
Assert.assertNotNull(\"查询结果为空!\", user1); - 
Assert.assertEquals(\"查询结果错误!\", \"admin\", user1.getName()); - 
} - 
/** - 
* Mock测试:保存user - 
*/ - 
@Mock - 
private UserDao userDao; - 
@InjectMocks - 
private UserServiceImpl userService; - 
@Test - 
public void saveUserTest() throws Exception{ - 
// 执行注解初始化 - 
MockitoAnnotations.initMocks(this); - 
// mock对象stub操作 - 
final User user = new User(); - 
user.setName(\"admin\"); - 
user.setPassword(\"pass\"); - 
when(userDao.getUserByName(\"admin\")).thenReturn(user).thenReturn(null); - 
when(userDao.saveUser(any(User.class))).thenReturn(1); - 
// 验证用户名重复的情况 - 
try { - 
userService.saveUser(user); - 
throw new Exception(); //走到这里说明验证失败 - 
} catch (RuntimeException e) { - 
System.out.println(\"重复用户名保存失败-测试通过\"); //重复用户名保存失败-测试通过 - 
} - 
verify(userDao).getUserByName(\"admin\"); - 
// 验证正常保存的情况 - 
user.setName(\"user\"); - 
final Integer integer = userService.saveUser(user); - 
System.out.println(\"保存结果:\" + integer); //保存结果:1 - 
Assert.assertEquals(\"保存失败!\", 1, integer.longValue()); - 
verify(userDao).saveUser(any(User.class)); - 
verify(userDao, times(2)).getUserByName(anyString()); - 
} 
根据以上代码我们可以知道,当我们的待测类开发完成而依赖的类的实现还没有开发完成。此时,我们就可以用到我们的Mock测试,模拟我们依赖类的返回值,使我们的待测类与依赖类解耦。这样,我们就可以对我们的待测类进行单元测了。
四、参考文档及进一步学习~
- 
Mockito英文版javadoc:https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/Mockito.html - 
Mockito中文文档(部分):https://blog.csdn.net/bboyfeiyu/article/details/52127551#35 - 
Mockito使用教程:https://www.cnblogs.com/Ming8006/p/6297333.html - 
参数捕获器使用:https://www.journaldev.com/21892/mockito-argumentcaptor-captor-annotation - 
利用ArgumentCaptor(参数捕获器)捕获方法参数进行验证:https://www.iteye.com/blog/hotdog-916364 - 
改变mock返回值:https://www.huangyunkun.com/2014/10/25/mockito-deep-stub-with-enum/ - 
五分钟了解Mockito:https://www.iteye.com/blog/liuzhijun-1512780 - 
使用Mockito进行单元测试:https://www.iteye.com/blog/qiuguo0205-1443344 - 
JUnit + Mockito 单元测试:https://blog.csdn.net/zhangxin09/article/details/42422643 - 
Mockito中@Mock与@InjectMock:https://www.cnblogs.com/langren1992/p/9681600.html - 
mockito中两种部分mock的实现,spy、callRealMethod:https://www.cnblogs.com/softidea/p/4204389.html - 
Mockito 中被 Mocked 的对象属性及方法的默认值:https://www.cnblogs.com/fnlingnzb-learner/p/10635250.html - 
单元测试工具之Mockito:https://blog.csdn.net/qq_32140971/article/details/90598454 - 
引入Mockito测试用@Spy和@Mock:https://blog.csdn.net/message_lx/article/details/83308114 - 
Mockito初探(含实例):https://www.iteye.com/blog/sgq0085-2031319 - 
测试覆盖率统计:https://blog.csdn.net/lvyuan1234/article/details/82836052?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task - 
测试覆盖率无法统计解决:https://blog.csdn.net/zhanglei082319/article/details/81536398 
如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!
最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】




