一文浅谈Mockito使用 | 京东云技术团队

一、前期准备~

1、准备工作

1<!--mockito依赖-->a 2<dependency> 3 <groupId>org.mockito</groupId> 4 <artifactId>mockito-core</artifactId> 5 <version>2.7.19</version> 6 <scope>test</scope> 7</dependency> 8<!-- junit依赖 --> 9<dependency> 10 <groupId>junit</groupId> 11 <artifactId>junit</artifactId> 12 <version>4.12</version> 13 <scope>test</scope> 14</dependency> 15

2、入门知识

11)Mockito:简单轻量级的做mocking测试的框架; 22)mock对象:在调试期间用来作为真实对象的替代品; 33)mock测试:在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试; 44)stub:打桩,就是为mock对象的方法指定返回值(可抛出异常); 55)verify:行为验证,验证指定方法调用情况(是否被调用,调用次数等); 6

3、五分钟入门Demo

1@Test 2public void test0() { 3 //1、创建mock对象(模拟依赖的对象) 4 final List mock = Mockito.mock(List.class); 5 6 //2、使用mock对象(mock对象会对接口或类的方法给出默认实现) 7 System.out.println("mock.add result => " + mock.add("first")); //false 8 System.out.println("mock.size result => " + mock.size()); //0 9 10 //3、打桩操作(状态测试:设置该对象指定方法被调用时的返回值) 11 Mockito.when(mock.get(0)).thenReturn("second"); 12 Mockito.doReturn(66).when(mock).size(); 13 14 //3、使用mock对象的stub(测试打桩结果) 15 System.out.println("mock.get result => " + mock.get(0)); //second 16 System.out.println("mock.size result => " + mock.size()); //66 17 18 //4、验证交互 verification(行为测试:验证方法调用情况) 19 Mockito.verify(mock).get(Mockito.anyInt()); 20 Mockito.verify(mock, Mockito.times(2)).size(); 21 22 //5、验证返回的结果(这是JUnit的功能) 23 assertEquals("second", mock.get(0)); 24 assertEquals(66, mock.size()); 25} 26

二、让我们开始学习吧!

1、行为验证

• 一旦mock对象被创建了,mock对象会记住所有的交互,然后你就可以选择性的验证你感兴趣的交互,验证不通过则抛出异常。

1@Test 2public void test1() { 3 final List mockList = Mockito.mock(List.class); 4 mockList.add("mock1"); 5 mockList.get(0); 6 mockList.size(); 7 mockList.clear(); 8 // 验证方法被使用(默认1次) 9 Mockito.verify(mockList).add("mock1"); 10 // 验证方法被使用1次 11 Mockito.verify(mockList, Mockito.times(1)).get(0); 12 // 验证方法至少被使用1次 13 Mockito.verify(mockList, Mockito.atLeast(1)).size(); 14 // 验证方法没有被使用 15 Mockito.verify(mockList, Mockito.never()).contains("mock2"); 16 // 验证方法至多被使用5次 17 Mockito.verify(mockList, Mockito.atMost(5)).clear(); 18 // 指定方法调用超时时间 19 Mockito.verify(mockList, timeout(100)).get(0); 20 // 指定时间内需要完成的次数 21 Mockito.verify(mockList, timeout(200).atLeastOnce()).size(); 22} 23

2、如何做一些测试桩stub

• 默认情况下,所有的函数都有返回值。mock函数默认返回的是null,一个空的集合或者一个被对象类型包装的内置类型,例如0、false对应的对象类型为Integer、Boolean;

• 一旦测试桩函数被调用,该函数将会一致返回固定的值;

• 对于 static 和 final 方法, Mockito 无法对其 when(…).thenReturn(…) 操作。

1@Test 2public void test2() { 3 //静态导入,减少代码量:import static org.mockito.Mockito.*; 4 final ArrayList mockList = mock(ArrayList.class); 5 6 // 设置方法调用返回值 7 when(mockList.add("test2")).thenReturn(true); 8 doReturn(true).when(mockList).add("test2"); 9 System.out.println(mockList.add("test2")); //true 10 11 // 设置方法调用抛出异常 12 when(mockList.get(0)).thenThrow(new RuntimeException()); 13 doThrow(new RuntimeException()).when(mockList).get(0); 14 System.out.println(mockList.get(0)); //throw RuntimeException 15 16 // 无返回方法打桩 17 doNothing().when(mockList).clear(); 18 19 // 为回调做测试桩(对方法返回进行拦截处理) 20 final Answer<String> answer = new Answer<String>() { 21 @Override 22 public String answer(InvocationOnMock invocationOnMock) throws Throwable { 23 final List mock = (List) invocationOnMock.getMock(); 24 return "mock.size result => " + mock.size(); 25 } 26 }; 27 when(mockList.get(1)).thenAnswer(answer); 28 doAnswer(answer).when(mockList).get(1); 29 System.out.println(mockList.get(1)); //mock.size result => 0 30 31 // 对同一方法多次打桩,以最后一次为准 32 when(mockList.get(2)).thenReturn("test2_1"); 33 when(mockList.get(2)).thenReturn("test2_2"); 34 System.out.println(mockList.get(2)); //test2_2 35 System.out.println(mockList.get(2)); //test2_2 36 37 // 设置多次调用同类型结果 38 when(mockList.get(3)).thenReturn("test2_1", "test2_2"); 39 when(mockList.get(3)).thenReturn("test2_1").thenReturn("test2_2"); 40 System.out.println(mockList.get(3)); //test2_1 41 System.out.println(mockList.get(3)); //test2_2 42 43 // 为连续调用做测试桩(为同一个函数调用的不同的返回值或异常做测试桩) 44 when(mockList.get(4)).thenReturn("test2").thenThrow(new RuntimeException()); 45 doReturn("test2").doThrow(new RuntimeException()).when(mockList).get(4); 46 System.out.println(mockList.get(4)); //test2 47 System.out.println(mockList.get(4)); //throw RuntimeException 48 49 // 无打桩方法,返回默认值 50 System.out.println(mockList.get(99)); //null 51} 52

3、参数匹配器

• 参数匹配器使验证和测试桩变得更灵活;

• 为了合理的使用复杂的参数匹配,使用equals()与anyX() 的匹配器会使得测试代码更简洁、简单。有时,会迫使你重构代码以使用equals()匹配或者实现equals()函数来帮助你进行测试;

• 如果你使用参数匹配器,所有参数都必须由匹配器提供;

• 支持自定义参数匹配器;

1@Test 2public void test3() { 3 final Map mockMap = mock(Map.class); 4 5 // 正常打桩测试 6 when(mockMap.get("key")).thenReturn("value1"); 7 System.out.println(mockMap.get("key")); //value1 8 9 // 为灵活起见,可使用参数匹配器 10 when(mockMap.get(anyString())).thenReturn("value2"); 11 System.out.println(mockMap.get(anyString())); //value2 12 System.out.println(mockMap.get("test_key")); //value2 13 System.out.println(mockMap.get(0)); //null 14 15 // 多个入参时,要么都使用参数匹配器,要么都不使用,否则会异常 16 when(mockMap.put(anyString(), anyInt())).thenReturn("value3"); 17 System.out.println(mockMap.put("key3", 3)); //value3 18 System.out.println(mockMap.put(anyString(), anyInt())); //value3 19 System.out.println(mockMap.put("key3", anyInt())); //异常 20 21 // 行为验证时,也支持使用参数匹配器 22 verify(mockMap, atLeastOnce()).get(anyString()); 23 verify(mockMap).put(anyString(), eq(3)); 24 25 // 自定义参数匹配器 26 final ArgumentMatcher<ArgumentTestRequest> myArgumentMatcher = new ArgumentMatcher<ArgumentTestRequest>() { 27 @Override 28 public boolean matches(ArgumentTestRequest request) { 29 return "name".equals(request.getName()) || "value".equals(request.getValue()); 30 } 31 }; 32 // 自定义参数匹配器使用 33 final ArgumentTestService mock = mock(ArgumentTestService.class); 34 when(mock.argumentTestMethod(argThat(myArgumentMatcher))).thenReturn("success"); 35 doReturn("success").when(mock).argumentTestMethod(argThat(myArgumentMatcher)); 36 System.out.println(mock.argumentTestMethod(new ArgumentTestRequest("name", "value"))); // success 37 System.out.println(mock.argumentTestMethod(new ArgumentTestRequest())); //null 38} 39

4、执行顺序验证

• 验证执行顺序是非常灵活的-你不需要一个一个的验证所有交互,只需要验证你感兴趣的对象即可;

• 你可以仅通过那些需要验证顺序的mock对象来创建InOrder对象;

1@Test 2public void test4() { 3 // 验证同一个对象多个方法的执行顺序 4 final List mockList = mock(List.class); 5 mockList.add("first"); 6 mockList.add("second"); 7 final InOrder inOrder = inOrder(mockList); 8 inOrder.verify(mockList).add("first"); 9 inOrder.verify(mockList).add("second"); 10 11 // 验证多个对象多个方法的执行顺序 12 final List mockList1 = mock(List.class); 13 final List mockList2 = mock(List.class); 14 mockList1.get(0); 15 mockList1.get(1); 16 mockList2.get(0); 17 mockList1.get(2); 18 mockList2.get(1); 19 final InOrder inOrder1 = inOrder(mockList1, mockList2); 20 inOrder1.verify(mockList1).get(0); 21 inOrder1.verify(mockList1).get(2); 22 inOrder1.verify(mockList2).get(1); 23} 24

5、确保交互(interaction)操作不会执行在mock对象上

• 一些用户可能会在频繁地使用verifyNoMoreInteractions(),甚至在每个测试函数中都用。但是verifyNoMoreInteractions()并不建议在每个测试函数中都使用;

• verifyNoMoreInteractions()在交互测试套件中只是一个便利的验证,它的作用是当你需要验证是否存在冗余调用时;

1@Test 2public void test5() { 3 // 验证某个交互是否从未被执行 4 final List mock = mock(List.class); 5 mock.add("first"); 6 verify(mock, never()).add("test5"); //通过 7 verify(mock, never()).add("first"); //异常 8 9 // 验证mock对象没有交互过 10 final List mock1 = mock(List.class); 11 final List mock2 = mock(List.class); 12 verifyZeroInteractions(mock1); //通过 13 verifyNoMoreInteractions(mock1, mock2); //通过 14 verifyZeroInteractions(mock, mock2); //异常 15 16 // 注意:可能只想验证前面的逻辑,但是加上最后一行,会导致出现异常。建议使用方法层面的验证,如:never(); 17 // 在验证是否有冗余调用的时候,可使用此种方式。如下: 18 final List mockList = mock(List.class); 19 mockList.add("one"); 20 mockList.add("two"); 21 verify(mockList).add("one"); // 通过 22 verify(mockList, never()).get(0); //通过 23 verifyZeroInteractions(mockList); //异常 24} 25

6、使用注解简化mock对象创建

注意!下面这句代码需要在运行测试函数之前被调用,一般放到测试类的基类或者test runner中:

1MockitoAnnotations.initMocks(this); 2

也可以使用内置的runner: MockitoJUnitRunner 或者一个rule : MockitoRule;

1// 代替 mock(ArgumentTestService.class) 创建mock对象; 2@Mock 3private ArgumentTestService argumentTestService; 4// 若改注解修饰的对象有成员变量,@Mock定义的mock对象会被自动注入; 5@InjectMocks 6private MockitoAnnotationServiceImpl mockitoAnnotationService; 7 8@Test 9public void test6() { 10 // 注意!下面这句代码需要在运行测试函数之前被调用,一般放到测试类的基类或者test runner中; 11 MockitoAnnotations.initMocks(this); 12 when(argumentTestService.argumentTestMethod(new ArgumentTestRequest())).thenReturn("success"); 13 System.out.println(argumentTestService.argumentTestMethod(new ArgumentTestRequest())); //success 14 System.out.println(mockitoAnnotationService.mockitoAnnotationTestMethod()); //null 15} 16

7、监控真实对象(部分mock)

• 可以为真实对象创建一个监控(spy)对象。当你使用这个spy对象时真实的对象也会也调用,除非它的函数被stub了;

• 尽量少使用spy对象,使用时也需要小心形式,例如spy对象可以用来处理遗留代码;

• stub语法中同样提供了部分mock的方法,可以调用真实的方法;

完全mock:

上文讲的内容是完全mock,即创建的mock对象与真实对象无关,mock对象的方法默认都是基本的实现,返回基本类型。可基于接口、实现类创建mock对象。

部分mock:

所谓部分mock,即创建的mock对象时基于真实对象的,mock对象的方法都是默认使用真实对象的方法,除非stub之后,才会以stub为准。基于实现类创建mock对象,否则在没有stub的情况下,调用真实方法时,会出现异常。

注意点:

Mockito并不会为真实对象代理函数调用,实际上它会拷贝真实对象。因此如果你保留了真实对象并且与之交互,不要期望从监控对象得到正确的结果。 当你在监控对象上调用一个没有被stub的函数时并不会调用真实对象的对应函数,你不会在真实对象上看到任何效果

1@Test 2public void test7() { 3 // stub部分mock(stub中使用真实调用)。注意:需要mock实现类,否则会有异常 4 final StubTestService stubTestService = mock(StubTestServiceImpl.class); 5 when(stubTestService.stubTestMethodA("paramA")).thenCallRealMethod(); 6 doCallRealMethod().when(stubTestService).stubTestMethodB(); 7 System.out.println(stubTestService.stubTestMethodA("paramA")); //stubTestMethodA is called, param = paramA 8 System.out.println(stubTestService.stubTestMethodB()); //stubTestMethodB is called 9 System.out.println(stubTestService.stubTestMethodC()); //null 10 11 // spy部分mock 12 final LinkedList<String> linkedList = new LinkedList(); 13 final LinkedList spy = spy(linkedList); 14 spy.add("one"); 15 spy.add("two"); 16 doReturn(100).when(spy).size(); 17 when(spy.get(0)).thenReturn("one_test"); 18 System.out.println(spy.size()); //100 19 System.out.println(spy.get(0)); //one_test 20 System.out.println(spy.get(1)); //two 21 22 // spy可以类比AOP。在spy中,由于默认是调用真实方法,所以第二种写法不等价于第一种写法,不推荐这种写法。 23 doReturn("two_test").when(spy).get(2); 24 when(spy.get(2)).thenReturn("two_test"); //异常 java.lang.IndexOutOfBoundsException: Index: 2, Size: 2 25 System.out.println(spy.get(2)); //two_test 26 27 // spy对象只是真实对象的复制,真实对象的改变不会影响spy对象 28 final List<String> arrayList = new ArrayList<>(); 29 final List<String> spy1 = spy(arrayList); 30 spy1.add(0, "one"); 31 System.out.println(spy1.get(0)); //one 32 arrayList.add(0, "list1"); 33 System.out.println(arrayList.get(0)); //list1 34 System.out.println(spy1.get(0)); //one 35 36 // 若对某个方法stub之后,又想调用真实的方法,可以使用reset(spy) 37 final ArrayList<String> arrayList1 = new ArrayList<>(); 38 final ArrayList<String> spy2 = spy(arrayList1); 39 doReturn(100).when(spy2).size(); 40 System.out.println(spy2.size()); //100 41 reset(spy2); 42 System.out.println(spy2.size()); //0 43} 44

8、@Mock 和 @Spy的使用

@Mock 等价于 Mockito.mock(Object.class);

@Spy 等价于 Mockito.spy(obj);

1区分是mock对象还是spy对象: 2Mockito.mockingDetails(someObject).isMock(); 3Mockito.mockingDetails(someObject).isSpy(); 4 5@Mock 6private StubTestService stubTestService; 7@Spy 8private StubTestServiceImpl stubTestServiceImpl; 9@Spy 10private StubTestService stubTestServiceImpl1 = new StubTestServiceImpl(); 11@Test 12public void test8() { 13 MockitoAnnotations.initMocks(this); 14 // mock对象返回默认 15 System.out.println(stubTestService.stubTestMethodB()); //null 16 // spy对象调用真实方法 17 System.out.println(stubTestServiceImpl.stubTestMethodC()); //stubTestMethodC is called 18 System.out.println(stubTestServiceImpl1.stubTestMethodA("spy")); //stubTestMethodA is called, param = spy 19 20 // 区分是mock对象还是spy对象 21 System.out.println(mockingDetails(stubTestService).isMock()); //true 22 System.out.println(mockingDetails(stubTestService).isSpy()); //false 23 System.out.println(mockingDetails(stubTestServiceImpl).isSpy()); //true 24} 25

9、ArgumentCaptor(参数捕获器)捕获方法参数进行验证。(可代替参数匹配器使用)

• 在某些场景中,不光要对方法的返回值和调用进行验证,同时需要验证一系列交互后所传入方法的参数。那么我们可以用参数捕获器来捕获传入方法的参数进行验证,看它是否符合我们的要求。

ArgumentCaptor介绍

通过ArgumentCaptor对象的forClass(Class

ArgumentCaptor的Api

argument.capture() 捕获方法参数

argument.getValue() 获取方法参数值,如果方法进行了多次调用,它将返回最后一个参数值

argument.getAllValues() 方法进行多次调用后,返回多个参数值

1@Test 2public void test9() { 3 List mock = mock(List.class); 4 List mock1 = mock(List.class); 5 mock.add("John"); 6 mock1.add("Brian"); 7 mock1.add("Jim"); 8 // 获取方法参数 9 ArgumentCaptor argument = ArgumentCaptor.forClass(String.class); 10 verify(mock).add(argument.capture()); 11 System.out.println(argument.getValue()); //John 12 13 // 多次调用获取最后一次 14 ArgumentCaptor argument1 = ArgumentCaptor.forClass(String.class); 15 verify(mock1, times(2)).add(argument1.capture()); 16 System.out.println(argument1.getValue()); //Jim 17 18 // 获取所有调用参数 19 System.out.println(argument1.getAllValues()); //[Brian, Jim] 20} 21

10、简化 ArgumentCaptor 的创建

1@Mock 2private List<String> captorList; 3@Captor 4private ArgumentCaptor<String> argumentCaptor; 5@Test 6public void test10() { 7 MockitoAnnotations.initMocks(this); 8 captorList.add("cap1"); 9 captorList.add("cap2"); 10 System.out.println(captorList.size()); 11 verify(captorList, atLeastOnce()).add(argumentCaptor.capture()); 12 System.out.println(argumentCaptor.getAllValues()); 13} 14

11、高级特性:自定义验证失败信息

1@Test 2public void test11() { 3 final ArrayList arrayList = mock(ArrayList.class); 4 arrayList.add("one"); 5 arrayList.add("two"); 6 7 verify(arrayList, description("size()没有调用")).size(); 8 // org.mockito.exceptions.base.MockitoAssertionError: size()没有调用 9 10 verify(arrayList, timeout(200).times(3).description("验证失败")).add(anyString()); 11 //org.mockito.exceptions.base.MockitoAssertionError: 验证失败 12} 13

12、高级特性:修改没有测试桩的调用的默认返回值

• 可以指定策略来创建mock对象的返回值。这是一个高级特性,通常来说,你不需要写这样的测试;

• 它对于遗留系统来说是很有用处的。当你不需要为函数调用打桩时你可以指定一个默认的answer;

1@Test 2public void test12(){ 3 // 创建mock对象、使用默认返回 4 final ArrayList mockList = mock(ArrayList.class); 5 System.out.println(mockList.get(0)); //null 6 7 // 这个实现首先尝试全局配置,如果没有全局配置就会使用默认的回答,它返回0,空集合,null,等等。 8 // 参考返回配置:ReturnsEmptyValues 9 mock(ArrayList.class, Answers.RETURNS_DEFAULTS); 10 11 // ReturnsSmartNulls首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回SmartNull。 12 // 如果最终返回对象,那么会简单返回null。一般用在处理遗留代码。 13 // 参考返回配置:ReturnsMoreEmptyValues 14 mock(ArrayList.class, Answers.RETURNS_SMART_NULLS); 15 16 // 未stub的方法,会调用真实方法。 17 // 注1:存根部分模拟使用时(mock.getSomething ()) .thenReturn (fakeValue)语法将调用的方法。对于部分模拟推荐使用doReturn语法。 18 // 注2:如果模拟是序列化反序列化,那么这个Answer将无法理解泛型的元数据。 19 mock(ArrayList.class, Answers.CALLS_REAL_METHODS); 20 21 // 深度stub,用于嵌套对象的mock。参考:https://www.cnblogs.com/Ming8006/p/6297333.html 22 mock(ArrayList.class, Answers.RETURNS_DEEP_STUBS); 23 24 // ReturnsMocks首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回mock。 25 // 如果返回类型不能mocked(例如是final)然后返回null。 26 mock(ArrayList.class, Answers.RETURNS_MOCKS); 27 28 // mock对象的方法调用后,可以返回自己(类似builder模式) 29 mock(ArrayList.class, Answers.RETURNS_SELF); 30 31 // 自定义返回 32 final Answer<String> answer = new Answer<String>() { 33 @Override 34 public String answer(InvocationOnMock invocation) throws Throwable { 35 return "test_answer"; 36 } 37 }; 38 final ArrayList mockList1 = mock(ArrayList.class, answer); 39 System.out.println(mockList1.get(0)); //test_answer 40} 41

三、学习了这么多,牛刀小试一下!

测试实体类

1@Data 2public class User { 3 4 /** 5 * 姓名,登录密码 6 */ 7 8

持久层DAO

1public interface UserDao { 2 3 /** 4 * 根据name查找user 5 * @param name 6 * @return 7 */ 8 User getUserByName(String name); 9 10 /** 11 * 保存user 12 * @param user 13 * @return 14 */ 15 Integer saveUser(User user); 16} 17

业务层Service接口

1public interface UserService { 2 3 /** 4 * 根据name查找user 5 * @param name 6 * @return 7 */ 8 User getUserByName(String name); 9 10 /** 11 * 保存user 12 * @param user 13 * @return 14 */ 15 Integer saveUser(User user); 16} 17

业务层Serive实现类

1@Service 2public class UserServiceImpl implements UserService { 3 4 //userDao 5 @Autowired 6 private UserDao userDao; 7 8 /** 9 * 根据name查找user 10 * @param name 11 * @return 12 */ 13 @Override 14 public User getUserByName(String name) { 15 try { 16 return userDao.getUserByName(name); 17 } catch (Exception e) { 18 throw new RuntimeException("查询user异常"); 19 } 20 } 21 22 /** 23 * 保存user 24 * @param user 25 * @return 26 */ 27 @Override 28 public Integer saveUser(User user) { 29 if (userDao.getUserByName(user.getName()) != null) { 30 throw new RuntimeException("用户名已存在"); 31 } 32 try { 33 return userDao.saveUser(user); 34 } catch (Exception e) { 35 throw new RuntimeException("保存用户异常"); 36 } 37 } 38} 39

现在我们的Service写好了,想要单元测试一下,但是Dao是其他人开发的,目前还没有写好,那我们如何测试呢?

1public class UserServiceTest { 2 3 /** 4 * Mock测试:根据name查询user 5 */ 6 @Test 7 public void getUserByNameTest() { 8 // mock对象 9 final UserDao userDao = mock(UserDao.class); 10 final UserServiceImpl userService = new UserServiceImpl(); 11 userService.setUserDao(userDao); 12 13 // stub调用 14 final User user = new User(); 15 user.setName("admin"); 16 user.setPassword("pass"); 17 when(userDao.getUserByName("admin")).thenReturn(user); 18 19 // 执行待测试方法 20 final User user1 = userService.getUserByName("admin"); 21 System.out.println("查询结果:" + JacksonUtil.obj2json(user1)); //查询结果:{"name":"admin","password":"pass"} 22 23 // 验证mock对象交互 24 verify(userDao).getUserByName(anyString()); 25 26 // 验证查询结果 27 Assert.assertNotNull("查询结果为空!", user1); 28 Assert.assertEquals("查询结果错误!", "admin", user1.getName()); 29 } 30 31 32 /** 33 * Mock测试:保存user 34 */ 35 @Mock 36 private UserDao userDao; 37 @InjectMocks 38 private UserServiceImpl userService; 39 @Test 40 public void saveUserTest() throws Exception{ 41 // 执行注解初始化 42 MockitoAnnotations.initMocks(this); 43 44 // mock对象stub操作 45 final User user = new User(); 46 user.setName("admin"); 47 user.setPassword("pass"); 48 when(userDao.getUserByName("admin")).thenReturn(user).thenReturn(null); 49 when(userDao.saveUser(any(User.class))).thenReturn(1); 50 51 // 验证用户名重复的情况 52 try { 53 userService.saveUser(user); 54 throw new Exception(); //走到这里说明验证失败 55 } catch (RuntimeException e) { 56 System.out.println("重复用户名保存失败-测试通过"); //重复用户名保存失败-测试通过 57 } 58 verify(userDao).getUserByName("admin"); 59 60 // 验证正常保存的情况 61 user.setName("user"); 62 final Integer integer = userService.saveUser(user); 63 System.out.println("保存结果:" + integer); //保存结果:1 64 Assert.assertEquals("保存失败!", 1, integer.longValue()); 65 66 verify(userDao).saveUser(any(User.class)); 67 verify(userDao, times(2)).getUserByName(anyString()); 68 } 69 70} 71

根据以上代码我们可以知道,当我们的待测类开发完成而依赖的类的实现还没有开发完成。此时,我们就可以用到我们的Mock测试,模拟我们依赖类的返回值,使我们的待测类与依赖类解耦。这样,我们就可以对我们的待测类进行单元测了。

四、参考文档及进一步学习~

作者:京东零售 秦浩然

来源:京东云开发者社区 转载请注明来源

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

mysql中like用法

like的通配符有两种%(百分号):代表零个、一个或者多个字符。\(下划线):代表一个数字或者字符。1\.name以"李"开头wherenamelike'李%'2\.name中包含"云",“云”可以在任何位置wherenamelike'%云%'3\.第二个和第三个字符是0的值wheresalarylike'\00%'4\

List的Select 和Select().tolist()

List<PersondelpnewList<Person{newPerson{Id1,Name"小明1",Age11,Sign0},newPerson{Id2,Name"小明2",Age12,

FLV文件格式

1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.