Java单元测试之Mockito

Mockito

Mockito是一种Java Mock框架,主要就是用来做Mock测试的,它可以模拟任何Spring管理的Bean、模拟方法的返回值、模拟抛出异常等等,同时也会记录调用这些模拟方法的参数、调用顺序,从而可以校验出这个Mock对象是否有被正确的顺序调用,以及按照期望的参数被调用。

文章目录

  • Mockito
    • mockito的特别之处?
    • 什么是mockito的stub method?
    • doThrow
    • mockito mock一个返回值为void的函数
    • 解决单元测试Mockito模拟方法内new对象的问题
    • doReturn().when()与when().thenReturn()
    • mockito怎么mock final修饰的类?

mockito的特别之处?

Mockito的特别之处在于它是一个强大的用于Java开发的模拟测试框架,通过Mockito我们可以创建和配置Mock对象,进而简化有外部依赖的类的测试。Mockito提供了大量的静态方法,用于帮助我们来mock对象,验证行为等等

什么是mockito的stub method?

本人的理解:就是在实际调用代码前,我就规定它返回什么。
一个例子:

// 您可以模拟具体的类,而不仅仅是接口s 
LinkedList mockedList = mock(LinkedList.class); 
// 或者使用Mockito 4.10.0+更简单
// LinkedList mockedList = mock(); 

// 存根(stubbing)在实际执行之前出现
when(mockedList.get(0)).thenReturn("first"); 
// 以下打印“first”
System.out.println(mockedList.get(0)); 
// 下面打印“null”,因为get(999)没有存根
System.out.println(mockedList.get(999));

doThrow

在测试对象发生特定事件时抛出异常。
例1:

PowerMockito
        .doThrow(new NotPermittedException(HttpServletResponse.SC_FORBIDDEN,
                ErrorMsgResourceKeys.auth_accessDenied, "GroupPermissions", null))
        .when(AdminPermissionCheck.class);
AdminPermissionCheck.checkAdminPermission(authorizationsVO, lstPermissions, true);

例2:

@Test
void whenConfigVoidRetunMethodToThrowEx_thenExIsThrown() {
    MyDictionary dictMock = mock(MyDictionary.class);
    doThrow(IllegalStateException.class).when(dictMock)
        .add(anyString(), anyString());
    assertThrows(IllegalStateException.class, () -> {
        dictMock.add("word", "meaning");
    });
}

mockito mock一个返回值为void的函数

最初接触 Mockito 还思考并尝试过如何用它来 mock 返回值为 void 的方法,然而 Google 查找到的一般都会说用 doThrow() 的办法

doThrow(new RuntimeException()).when(mockObject).methodWithVoidReturn();

因为无法使用常规的 when(mockObject.foo()).thenReturn(...) 的方法。

当时我就纳闷,为何我想 mock 一个返回值为 void 的方法,却是在模拟抛出一个异常,现在想来如果一个返回值为 void 的方法,为何要去 mock 这个方法呢?

回想一个我们要 mock 一个方法的意图是什么:

  1. 在特定输入参数的情况下期待需要的输出结果(返回值)
  2. 在方法抛出某种类型异常调用者作出的反应

对于 void 返回值的方法,如果要验证有没有被调用过几次可以在事后用 verify() 方法去断言。所以基本上对于 void 返回值的方法一般可不用去 mock 它,只需用 verify() 去验证,或者就是像前面一样模拟出现异常时的情况。

解决单元测试Mockito模拟方法内new对象的问题

解决单元测试Mockito模拟方法内new对象的问题_mockito new_半斤米粉闯天下的博客-CSDN博客
记PowerMockito whenNew的一个坑_Brain_L的博客-CSDN博客
@PrepareForTest后面应该加上被测试的类,而不是要whenNew的类,被这个坑过两次了,特此记录下。

doReturn().when()与when().thenReturn()

java - doReturn().when()与when().thenReturn() - 成长之路 - SegmentFault 思否
doReturn().when()是无副作用的。
when().thenReturn()是有副作用的。
如果有时候报错missing thenReturn等问题,可以把(对象.方法)改为.(对象).方法

mockito怎么mock final修饰的类?

如果使用Mockito.mock(Gson.class),会报错:

Mockito cannot mock/spy because : - final class

这是因为低版本的mockito是不能mock final类的。

解决方案:Mockito不能mock final类的解决办法_南瓜慢说的博客-CSDN博客

改变mockito的版本,修改maven依赖如下:

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-inline</artifactId>
  <version>3.3.3</version>
</dependency>

重跑测试,问题解决!

然而,万一随意变动依赖导致其他test失效就得不偿失了,因此最好从业务逻辑上对代码进行改造,这里我们涉及的代码为:

Gson gson = new Gson();
String file = (String) gson.fromJson(result, Map.class).get("data");

Gson是final修饰的类,我们要调用它的fromJson方法,其实我们可以构造一个json格式的字符串result:

{data:logs}

然后fromJson就能正常调用了。

你可能感兴趣的:(java,单元测试)