【码农教程】手把手教你Mockito的使用

一、前期准备~
1、准备工作
  1. <!--mockito依赖-->

  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>

2、入门知识

1)Mockito:简单轻量级的做mocking测试的框架;

2)mock对象:在调试期间用来作为真实对象的替代品;

3)mock测试:在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试

4)stub:打桩,就是为mock对象的方法指定返回值(可抛出异常);

5)verify:行为验证,验证指定方法调用情况(是否被调用,调用次数等);

3、五分钟入门Demo
  1. @Test

  2. public void test0() {

  3. //1、创建mock对象(模拟依赖的对象)

  4. final List mock = Mockito.mock(List.class);

  5. //2、使用mock对象(mock对象会对接口或类的方法给出默认实现)

  6. System.out.println("mock.add result => " + mock.add("first")); //false

  7. System.out.println("mock.size result => " + mock.size()); //0

  8. //3、打桩操作(状态测试:设置该对象指定方法被调用时的返回值)

  9. Mockito.when(mock.get(0)).thenReturn("second");

  10. Mockito.doReturn(66).when(mock).size();

  11. //3、使用mock对象的stub(测试打桩结果)

  12. System.out.println("mock.get result => " + mock.get(0)); //second

  13. System.out.println("mock.size result => " + mock.size()); //66

  14. //4、验证交互 verification(行为测试:验证方法调用情况)

  15. Mockito.verify(mock).get(Mockito.anyInt());

  16. Mockito.verify(mock, Mockito.times(2)).size();

  17. //5、验证返回的结果(这是JUnit的功能)

  18. assertEquals("second", mock.get(0));

  19. assertEquals(66, mock.size());

  20. }

二、让我们开始学习吧!
1、行为验证

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

  1. @Test

  2. public 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. }

2、如何做一些测试桩stub

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

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

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

  1. @Test

  2. public void test2() {

  3. //静态导入,减少代码量:import static org.mockito.Mockito.*;

  4. final ArrayList mockList = mock(ArrayList.class);

  5. // 设置方法调用返回值

  6. when(mockList.add("test2")).thenReturn(true);

  7. doReturn(true).when(mockList).add("test2");

  8. System.out.println(mockList.add("test2")); //true

  9. // 设置方法调用抛出异常

  10. when(mockList.get(0)).thenThrow(new RuntimeException());

  11. doThrow(new RuntimeException()).when(mockList).get(0);

  12. System.out.println(mockList.get(0)); //throw RuntimeException

  13. // 无返回方法打桩

  14. doNothing().when(mockList).clear();

  15. // 为回调做测试桩(对方法返回进行拦截处理)

  16. final Answer<String> answer = new Answer<String>() {

  17. @Override

  18. public String answer(InvocationOnMock invocationOnMock) throws Throwable {

  19. final List mock = (List) invocationOnMock.getMock();

  20. return "mock.size result => " + mock.size();

  21. }

  22. };

  23. when(mockList.get(1)).thenAnswer(answer);

  24. doAnswer(answer).when(mockList).get(1);

  25. System.out.println(mockList.get(1)); //mock.size result => 0

  26. // 对同一方法多次打桩,以最后一次为准

  27. when(mockList.get(2)).thenReturn("test2_1");

  28. when(mockList.get(2)).thenReturn("test2_2");

  29. System.out.println(mockList.get(2)); //test2_2

  30. System.out.println(mockList.get(2)); //test2_2

  31. // 设置多次调用同类型结果

  32. when(mockList.get(3)).thenReturn("test2_1", "test2_2");

  33. when(mockList.get(3)).thenReturn("test2_1").thenReturn("test2_2");

  34. System.out.println(mockList.get(3)); //test2_1

  35. System.out.println(mockList.get(3)); //test2_2

  36. // 为连续调用做测试桩(为同一个函数调用的不同的返回值或异常做测试桩)

  37. when(mockList.get(4)).thenReturn("test2").thenThrow(new RuntimeException());

  38. doReturn("test2").doThrow(new RuntimeException()).when(mockList).get(4);

  39. System.out.println(mockList.get(4)); //test2

  40. System.out.println(mockList.get(4)); //throw RuntimeException

  41. // 无打桩方法,返回默认值

  42. System.out.println(mockList.get(99)); //null

  43. }

3、参数匹配器

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

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

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

支持自定义参数匹配器;

  1. @Test

  2. public void test3() {

  3. final Map mockMap = mock(Map.class);

  4. // 正常打桩测试

  5. when(mockMap.get("key")).thenReturn("value1");

  6. System.out.println(mockMap.get("key")); //value1

  7. // 为灵活起见,可使用参数匹配器

  8. when(mockMap.get(anyString())).thenReturn("value2");

  9. System.out.println(mockMap.get(anyString())); //value2

  10. System.out.println(mockMap.get("test_key")); //value2

  11. System.out.println(mockMap.get(0)); //null

  12. // 多个入参时,要么都使用参数匹配器,要么都不使用,否则会异常

  13. when(mockMap.put(anyString(), anyInt())).thenReturn("value3");

  14. System.out.println(mockMap.put("key3", 3)); //value3

  15. System.out.println(mockMap.put(anyString(), anyInt())); //value3

  16. System.out.println(mockMap.put("key3", anyInt())); //异常

  17. // 行为验证时,也支持使用参数匹配器

  18. verify(mockMap, atLeastOnce()).get(anyString());

  19. verify(mockMap).put(anyString(), eq(3));

  20. // 自定义参数匹配器

  21. final ArgumentMatcher<ArgumentTestRequest> myArgumentMatcher = new ArgumentMatcher<ArgumentTestRequest>() {

  22. @Override

  23. public boolean matches(ArgumentTestRequest request) {

  24. return "name".equals(request.getName()) || "value".equals(request.getValue());

  25. }

  26. };

  27. // 自定义参数匹配器使用

  28. final ArgumentTestService mock = mock(ArgumentTestService.class);

  29. when(mock.argumentTestMethod(argThat(myArgumentMatcher))).thenReturn("success");

  30. doReturn("success").when(mock).argumentTestMethod(argThat(myArgumentMatcher));

  31. System.out.println(mock.argumentTestMethod(new ArgumentTestRequest("name", "value"))); // success

  32. System.out.println(mock.argumentTestMethod(new ArgumentTestRequest())); //null

  33. }

4、执行顺序验证

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

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

  1. @Test

  2. public 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. final List mockList1 = mock(List.class);

  12. final List mockList2 = mock(List.class);

  13. mockList1.get(0);

  14. mockList1.get(1);

  15. mockList2.get(0);

  16. mockList1.get(2);

  17. mockList2.get(1);

  18. final InOrder inOrder1 = inOrder(mockList1, mockList2);

  19. inOrder1.verify(mockList1).get(0);

  20. inOrder1.verify(mockList1).get(2);

  21. inOrder1.verify(mockList2).get(1);

  22. }

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

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

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

  1. @Test

  2. public 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. // 验证mock对象没有交互过

  9. final List mock1 = mock(List.class);

  10. final List mock2 = mock(List.class);

  11. verifyZeroInteractions(mock1); //通过

  12. verifyNoMoreInteractions(mock1, mock2); //通过

  13. verifyZeroInteractions(mock, mock2); //异常

  14. // 注意:可能只想验证前面的逻辑,但是加上最后一行,会导致出现异常。建议使用方法层面的验证,如:never();

  15. // 在验证是否有冗余调用的时候,可使用此种方式。如下:

  16. final List mockList = mock(List.class);

  17. mockList.add("one");

  18. mockList.add("two");

  19. verify(mockList).add("one"); // 通过

  20. verify(mockList, never()).get(0); //通过

  21. verifyZeroInteractions(mockList); //异常

  22. }

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

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

MockitoAnnotations.initMocks(this);

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

  1. // 代替 mock(ArgumentTestService.class) 创建mock对象;

  2. @Mock

  3. private ArgumentTestService argumentTestService;

  4. // 若改注解修饰的对象有成员变量,@Mock定义的mock对象会被自动注入;

  5. @InjectMocks

  6. private MockitoAnnotationServiceImpl mockitoAnnotationService;

  7. @Test

  8. public void test6() {

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

  10. MockitoAnnotations.initMocks(this);

  11. when(argumentTestService.argumentTestMethod(new ArgumentTestRequest())).thenReturn("success");

  12. System.out.println(argumentTestService.argumentTestMethod(new ArgumentTestRequest())); //success

  13. System.out.println(mockitoAnnotationService.mockitoAnnotationTestMethod()); //null

  14. }

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

  2. public 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. // spy部分mock

  11. final LinkedList<String> linkedList = new LinkedList();

  12. final LinkedList spy = spy(linkedList);

  13. spy.add("one");

  14. spy.add("two");

  15. doReturn(100).when(spy).size();

  16. when(spy.get(0)).thenReturn("one_test");

  17. System.out.println(spy.size()); //100

  18. System.out.println(spy.get(0)); //one_test

  19. System.out.println(spy.get(1)); //two

  20. // spy可以类比AOP。在spy中,由于默认是调用真实方法,所以第二种写法不等价于第一种写法,不推荐这种写法。

  21. doReturn("two_test").when(spy).get(2);

  22. when(spy.get(2)).thenReturn("two_test"); //异常 java.lang.IndexOutOfBoundsException: Index: 2, Size: 2

  23. System.out.println(spy.get(2)); //two_test

  24. // spy对象只是真实对象的复制,真实对象的改变不会影响spy对象

  25. final List<String> arrayList = new ArrayList<>();

  26. final List<String> spy1 = spy(arrayList);

  27. spy1.add(0, "one");

  28. System.out.println(spy1.get(0)); //one

  29. arrayList.add(0, "list1");

  30. System.out.println(arrayList.get(0)); //list1

  31. System.out.println(spy1.get(0)); //one

  32. // 若对某个方法stub之后,又想调用真实的方法,可以使用reset(spy)

  33. final ArrayList<String> arrayList1 = new ArrayList<>();

  34. final ArrayList<String> spy2 = spy(arrayList1);

  35. doReturn(100).when(spy2).size();

  36. System.out.println(spy2.size()); //100

  37. reset(spy2);

  38. System.out.println(spy2.size()); //0

  39. }

8、@Mock 和 @Spy的使用

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

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

  1. 区分是mock对象还是spy对象:

  2. Mockito.mockingDetails(someObject).isMock();

  3. Mockito.mockingDetails(someObject).isSpy();

  4. @Mock

  5. private StubTestService stubTestService;

  6. @Spy

  7. private StubTestServiceImpl stubTestServiceImpl;

  8. @Spy

  9. private StubTestService stubTestServiceImpl1 = new StubTestServiceImpl();

  10. @Test

  11. public void test8() {

  12. MockitoAnnotations.initMocks(this);

  13. // mock对象返回默认

  14. System.out.println(stubTestService.stubTestMethodB()); //null

  15. // spy对象调用真实方法

  16. System.out.println(stubTestServiceImpl.stubTestMethodC()); //stubTestMethodC is called

  17. System.out.println(stubTestServiceImpl1.stubTestMethodA("spy")); //stubTestMethodA is called, param = spy

  18. // 区分是mock对象还是spy对象

  19. System.out.println(mockingDetails(stubTestService).isMock()); //true

  20. System.out.println(mockingDetails(stubTestService).isSpy()); //false

  21. System.out.println(mockingDetails(stubTestServiceImpl).isSpy()); //true

  22. }

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

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

ArgumentCaptor介绍

通过ArgumentCaptor对象的forClass(Class

ArgumentCaptor的Api

argument.capture() 捕获方法参数

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

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

  1. @Test

  2. public 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. ArgumentCaptor argument1 = ArgumentCaptor.forClass(String.class);

  14. verify(mock1, times(2)).add(argument1.capture());

  15. System.out.println(argument1.getValue()); //Jim

  16. // 获取所有调用参数

  17. System.out.println(argument1.getAllValues()); //[Brian, Jim]

  18. }

10、简化 ArgumentCaptor 的创建
  1. @Mock

  2. private List<String> captorList;

  3. @Captor

  4. private ArgumentCaptor<String> argumentCaptor;

  5. @Test

  6. public 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. }

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

  2. public void test11() {

  3. final ArrayList arrayList = mock(ArrayList.class);

  4. arrayList.add("one");

  5. arrayList.add("two");

  6. verify(arrayList, description("size()没有调用")).size();

  7. // org.mockito.exceptions.base.MockitoAssertionError: size()没有调用

  8. verify(arrayList, timeout(200).times(3).description("验证失败")).add(anyString());

  9. //org.mockito.exceptions.base.MockitoAssertionError: 验证失败

  10. }

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

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

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

  1. @Test

  2. public void test12(){

  3. // 创建mock对象、使用默认返回

  4. final ArrayList mockList = mock(ArrayList.class);

  5. System.out.println(mockList.get(0)); //null

  6. // 这个实现首先尝试全局配置,如果没有全局配置就会使用默认的回答,它返回0,空集合,null,等等。

  7. // 参考返回配置:ReturnsEmptyValues

  8. mock(ArrayList.class, Answers.RETURNS_DEFAULTS);

  9. // ReturnsSmartNulls首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回SmartNull。

  10. // 如果最终返回对象,那么会简单返回null。一般用在处理遗留代码。

  11. // 参考返回配置:ReturnsMoreEmptyValues

  12. mock(ArrayList.class, Answers.RETURNS_SMART_NULLS);

  13. // 未stub的方法,会调用真实方法。

  14. // 注1:存根部分模拟使用时(mock.getSomething ()) .thenReturn (fakeValue)语法将调用的方法。对于部分模拟推荐使用doReturn语法。

  15. // 注2:如果模拟是序列化反序列化,那么这个Answer将无法理解泛型的元数据。

  16. mock(ArrayList.class, Answers.CALLS_REAL_METHODS);

  17. // 深度stub,用于嵌套对象的mock。参考:https://www.cnblogs.com/Ming8006/p/6297333.html

  18. mock(ArrayList.class, Answers.RETURNS_DEEP_STUBS);

  19. // ReturnsMocks首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回mock。

  20. // 如果返回类型不能mocked(例如是final)然后返回null。

  21. mock(ArrayList.class, Answers.RETURNS_MOCKS);

  22. // mock对象的方法调用后,可以返回自己(类似builder模式)

  23. mock(ArrayList.class, Answers.RETURNS_SELF);

  24. // 自定义返回

  25. final Answer<String> answer = new Answer<String>() {

  26. @Override

  27. public String answer(InvocationOnMock invocation) throws Throwable {

  28. return "test_answer";

  29. }

  30. };

  31. final ArrayList mockList1 = mock(ArrayList.class, answer);

  32. System.out.println(mockList1.get(0)); //test_answer

  33. }

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

测试实体类

  1. @Data

  2. public class User {

  3. /**

  4. * 姓名,登录密码

  5. */

持久层DAO

  1. public interface UserDao {

  2. /**

  3. * 根据name查找user

  4. * @param name

  5. * @return

  6. */

  7. User getUserByName(String name);

  8. /**

  9. * 保存user

  10. * @param user

  11. * @return

  12. */

  13. Integer saveUser(User user);

  14. }

业务层Service接口

  1. public interface UserService {

  2. /**

  3. * 根据name查找user

  4. * @param name

  5. * @return

  6. */

  7. User getUserByName(String name);

  8. /**

  9. * 保存user

  10. * @param user

  11. * @return

  12. */

  13. Integer saveUser(User user);

  14. }

业务层Serive实现类

  1. @Service

  2. public class UserServiceImpl implements UserService {

  3. //userDao

  4. @Autowired

  5. private UserDao userDao;

  6. /**

  7. * 根据name查找user

  8. * @param name

  9. * @return

  10. */

  11. @Override

  12. public User getUserByName(String name) {

  13. try {

  14. return userDao.getUserByName(name);

  15. } catch (Exception e) {

  16. throw new RuntimeException("查询user异常");

  17. }

  18. }

  19. /**

  20. * 保存user

  21. * @param user

  22. * @return

  23. */

  24. @Override

  25. public Integer saveUser(User user) {

  26. if (userDao.getUserByName(user.getName()) != null) {

  27. throw new RuntimeException("用户名已存在");

  28. }

  29. try {

  30. return userDao.saveUser(user);

  31. } catch (Exception e) {

  32. throw new RuntimeException("保存用户异常");

  33. }

  34. }

  35. }

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

  1. public class UserServiceTest {

  2. /**

  3. * Mock测试:根据name查询user

  4. */

  5. @Test

  6. public void getUserByNameTest() {

  7. // mock对象

  8. final UserDao userDao = mock(UserDao.class);

  9. final UserServiceImpl userService = new UserServiceImpl();

  10. userService.setUserDao(userDao);

  11. // stub调用

  12. final User user = new User();

  13. user.setName("admin");

  14. user.setPassword("pass");

  15. when(userDao.getUserByName("admin")).thenReturn(user);

  16. // 执行待测试方法

  17. final User user1 = userService.getUserByName("admin");

  18. System.out.println("查询结果:" + JacksonUtil.obj2json(user1)); //查询结果:{"name":"admin","password":"pass"}

  19. // 验证mock对象交互

  20. verify(userDao).getUserByName(anyString());

  21. // 验证查询结果

  22. Assert.assertNotNull("查询结果为空!", user1);

  23. Assert.assertEquals("查询结果错误!", "admin", user1.getName());

  24. }

  25. /**

  26. * Mock测试:保存user

  27. */

  28. @Mock

  29. private UserDao userDao;

  30. @InjectMocks

  31. private UserServiceImpl userService;

  32. @Test

  33. public void saveUserTest() throws Exception{

  34. // 执行注解初始化

  35. MockitoAnnotations.initMocks(this);

  36. // mock对象stub操作

  37. final User user = new User();

  38. user.setName("admin");

  39. user.setPassword("pass");

  40. when(userDao.getUserByName("admin")).thenReturn(user).thenReturn(null);

  41. when(userDao.saveUser(any(User.class))).thenReturn(1);

  42. // 验证用户名重复的情况

  43. try {

  44. userService.saveUser(user);

  45. throw new Exception(); //走到这里说明验证失败

  46. } catch (RuntimeException e) {

  47. System.out.println("重复用户名保存失败-测试通过"); //重复用户名保存失败-测试通过

  48. }

  49. verify(userDao).getUserByName("admin");

  50. // 验证正常保存的情况

  51. user.setName("user");

  52. final Integer integer = userService.saveUser(user);

  53. System.out.println("保存结果:" + integer); //保存结果:1

  54. Assert.assertEquals("保存失败!", 1, integer.longValue());

  55. verify(userDao).saveUser(any(User.class));

  56. verify(userDao, times(2)).getUserByName(anyString());

  57. }

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

四、参考文档及进一步学习~
  1. Mockito英文版javadoc:https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/Mockito.html

  2. Mockito中文文档(部分):https://blog.csdn.net/bboyfeiyu/article/details/52127551#35

  3. Mockito使用教程:https://www.cnblogs.com/Ming8006/p/6297333.html

  4. 参数捕获器使用:https://www.journaldev.com/21892/mockito-argumentcaptor-captor-annotation

  5. 利用ArgumentCaptor(参数捕获器)捕获方法参数进行验证:https://www.iteye.com/blog/hotdog-916364

  6. 改变mock返回值:https://www.huangyunkun.com/2014/10/25/mockito-deep-stub-with-enum/

  7. 五分钟了解Mockito:https://www.iteye.com/blog/liuzhijun-1512780

  8. 使用Mockito进行单元测试:https://www.iteye.com/blog/qiuguo0205-1443344

  9. JUnit + Mockito 单元测试:https://blog.csdn.net/zhangxin09/article/details/42422643

  10. Mockito中@Mock与@InjectMock:https://www.cnblogs.com/langren1992/p/9681600.html

  11. mockito中两种部分mock的实现,spy、callRealMethod:https://www.cnblogs.com/softidea/p/4204389.html

  12. Mockito 中被 Mocked 的对象属性及方法的默认值:https://www.cnblogs.com/fnlingnzb-learner/p/10635250.html

  13. 单元测试工具之Mockito:https://blog.csdn.net/qq_32140971/article/details/90598454

  14. 引入Mockito测试用@Spy和@Mock:https://blog.csdn.net/message_lx/article/details/83308114

  15. Mockito初探(含实例):https://www.iteye.com/blog/sgq0085-2031319

  16. 测试覆盖率统计:https://blog.csdn.net/lvyuan1234/article/details/82836052?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

  17. 测试覆盖率无法统计解决:https://blog.csdn.net/zhanglei082319/article/details/81536398

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

Mockito是一个用于Java的开源测试框架,用于创建和管理模拟对象(mock objects)。它可以帮助我们进行单元测试,特别是在测试依赖对象时非常有用。 在Mockito中,我们可以使用注解来简化模拟对象的创建。例如,使用`@Mock`注解可以创建一个模拟对象,使用`@InjectMocks`注解可以将模拟对象注入到被测试对象中。 Mockito还提供了一些方法来验证模拟对象的交互和行为。例如,使用`verify`方法可以验证方法是否被调用,使用`times`方法可以指定方法被调用的次数,使用`never`方法可以验证方法是否从未被调用。 另外,Mockito还支持设置模拟对象的行为。我们可以使用`when`方法来设置模拟对象方法的返回值,使用`doReturn`方法来设置模拟对象方法的行为。 总之,Mockito是一个强大的测试框架,可以帮助我们进行单元测试,并且使用注解可以简化模拟对象的创建。通过验证和设置模拟对象的行为,我们可以更好地测试我们的代码。 #### 引用[.reference_title] - *1* *2* *3* [【码农教程手把手Mockito使用](https://blog.csdn.net/AI_Green/article/details/129163693)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值