0


mockito+junit完成单元测试

一:单元测试的特点

  • 配合断言使用(可以杜绝System.out)
  • 可以重复执行
  • 不依赖环境
  • 不会对数据产生影响
  • spring的上下文环境不是必须的
  • 一般都需要配合mock类框架来实现

二:常用的mock类框架

mockito

官网:Mockito framework site

另外现在像powermock和JMockito现在都不常用了;

三:Mockito的单独使用

(1)mock对象和spy对象

方法插桩

方法不插桩

作用对象

最佳实践

mock

执行插桩逻辑

返回mock对象的默认值

类、接口

被测试类或其依赖

spy

执行插桩逻辑

调用真实方法

类、接口

被测试类

(2)初始化mock/spy对象的方式

方法一

方法二

方法三

junit4

@RunWith(MockitoJUnitRunner.class)+@Mock等注解

Mockito.mock(X.class)等静态方法

MockitoAnnotations.openMocks(this)+@Mock等注解

junit5

@ExtendWith(MockitoExtension.class)+@Mock等注解

四:具体实例操作

Controller层:

  1. @Slf4j
  2. @RestController
  3. @Validated
  4. public class UserController{
  5. @Resource
  6. private UserService userService;
  7. @GetMapping("/selectById")
  8. public UserVO selectById(@NotNull Long userId){
  9. return userService.selectById(userId);
  10. }
  11. @PostMapping("/add")
  12. public String add(@RequestBody @Validated UserAddReq addReq){
  13. userService.add(addReq.getUsername(),addReq.getPhone(),addReq.getfeatures());
  14. return ok;
  15. }
  16. }

方法一:@ExtendWith(MockitoExtension.class)+@Mock等注解

  1. @ExtendWith(MockitoExtension.class)
  2. public class InitMockSpyMethod1{
  3. @mock
  4. private UserService mockUserService;
  5. @Spy
  6. private UserService spyUserService;
  7. @Test
  8. public void test1(){
  9. //true 判断某对象是不是mock对象
  10. System.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());
  11. //false 判断某对象是不是apy对象
  12. System.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());
  13. //true 判断某对象是不是spy对象
  14. System.out.println("Mockito.mockingDetails(spyUserService).isSpy() = " + Mockito.mockingDetails(spyUserService).isSpy());
  15. //true 判断某对象是不是spy对象,因为spy是一种特殊的mock(spy对象是另一种不同类型的mock对象)
  16. System.out.println("Mockito.mockingDetails(spyUserService).isMock() = " + Mockito.mockingDetail(spyUserService).isMock());
  17. }
  18. }

spy对象是一种特殊的mock对象

方法二:Mockito.mock(X.class)等静态方法

  1. public class InitMockSpyMethod1{
  2. private UserService mockUserService;
  3. private UserService spyUserService;
  4. @BeforeEach
  5. public void init(){
  6. mockUserService = Mockito.mock(UserService.class);
  7. spyUserService = Mockito.spy(UserService.class);
  8. }
  9. @Test
  10. public void test1(){
  11. System.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());
  12. System.out.println("Mockito.mockingDetails(mockUserService).isSpy() = " + Mockito.mockingDetails(mockUserService).isSpy());
  13. System.out.println("Mockito.mockingDetails(spyUserService).isMock() = " + Mockito.mockingDetails(spyUserService).isMock());
  14. }
  15. }

方法三:MockitoAnnotations.openMocks(this)+@Mock等注解

  1. public class InitMockSpyMethod1{
  2. @mock
  3. private UserService mockUserService;
  4. @Spy
  5. private UserService spyUserService;
  6. @BeforeEach
  7. public void init(){
  8. MockitoAnnotations.openMocks(this);
  9. }
  10. @Test
  11. public void test1(){
  12. //true 判断某对象是不是mock对象
  13. System.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());
  14. //false 判断某对象是不是apy对象
  15. System.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());
  16. //true 判断某对象是不是spy对象
  17. System.out.println("Mockito.mockingDetails(spyUserService).isSpy() = " + Mockito.mockingDetails(spyUserService).isSpy());
  18. //true 判断某对象是不是spy对象,因为spy是一种特殊的mock(spy对象是另一种不同类型的mock对象)
  19. System.out.println("Mockito.mockingDetails(spyUserService).isMock() = " + Mockito.mockingDetail(spyUserService).isMock());
  20. }
  21. }

五:参数匹配

参数匹配指的是:通过方法签名(参数)来指定哪些方法调用需要处理被处理(插桩、verify验证)

对于mock对象不会调用真实方法,直接返回mock对象的默认值;

默认值(int)、null(UserVO)、空集合(list)

六:方法插桩

指定调用某个方法时的行为(stubbing),达到相互隔离的目的

  1. /**
  2. *测试插桩时的参数匹配
  3. */
  4. @Test
  5. public void test2(){
  6. UserUpdateReq userUpdateReq1 = new UserUpdateReq();
  7. userUpdateReq1.setId(1L);
  8. userUpdateReq1.setPhone("1L");
  9. //指定参数为userUpdateReq1时调用mockUserService.modifyById(userUpdateReq1);
  10. Mockito.doReturn(99).when(mockUserService).modifyById(userUpdateReq1);
  11. int result1 = mockUserService.modifyById(userUpdateReq1);
  12. //运行结果为99
  13. System.out.println("result1 = " + result1);
  14. UserUpdateReq userUpdateReq2 = new UserUpdateReq();
  15. userUpdateReq2.setId(2L);
  16. userUpdateReq2.setPhone("2L");
  17. int result2 = mockUserService.modifyById(userUpdateReq2);
  18. //运行结果为0
  19. System.out.println("result2 = " + result2);
  20. }

总结

是告诉mockito当传入的是下面的参数这个类型时,才对其进插桩,若不是这个值,则不用对它进行插桩

若想要拦截某种类型的任意对象,则需要运用到:

ArgumentMatchers.any拦截UserUpdateReq类型的任意对象

** 校验**:

add方法调用一次,校验通过。

  1. private UserService mockUserService;
  2. @Test
  3. public void test4(){
  4. List<String> features = new ArrayList<>();
  5. mockUserService.add("实验","123",festures);
  6. //校验参数为"乐之者","123",festures,features的add方法调用了1次
  7. Mockito.verify(mockUserService,Mockito.times(2)).add("实验","123",festures);
  8. //报错 ,要么都用要么就都别用
  9. // Mockito.verify(mockUserService,Mockito.times(2)).add("实验","123",festures);
  10. //此时可以校验通过
  11. Mockito.verify(mockUserService,Mockito.times(2)).add(anyString(),anyString(),anyList());
  12. }
  13. }

但是有一点需要牢记的,除了any,还有(anyLong,anyString...),注意他们都不包括null,如果传null,还是不能被匹配的。

通过插桩,指定方法的返回值:

void返回值方法插桩 :

插桩的两种方式:

多次插桩:

其中when(mockList.size()).thenReturn(1).thenReturn(2).thenReturn(3)可以简写为when(mockList.size()).thenReturn(1,2,3);

thenAnswer指定插桩逻辑:

执行真正的原始方法:

verify的使用:

@InjectMocks注解的使用

1.被@InjectMocks标注的属性必须是实现类,因为mockito会创建对应的实例对象,默认创建的对象就是未经过mockito处理的普通对象。因此常配合@spy注解使其变成默认调用真实方法的mock对象。

2.mockito会使用spy,最终的结果就是,会把userFeatureService给注入到InjectMocks标注的变量所对应的对象里面去。

注入的原理


本文转载自: https://blog.csdn.net/qq_46019713/article/details/143380547
版权归原作者 又菜又爱玩的晴晴 所有, 如有侵权,请联系我们删除。

“mockito+junit完成单元测试”的评论:

还没有评论