Mockito - java单元测试

原文地址

一.简介

Mockito是mocking框架,它让你用简洁的API做测试,简单易学,可读性强并且验证语法简洁。
官网: http://mockito.org
项目源码:https://github.com/mockito/mockito 
官方文档:https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/Mockito.html

PS:文中所有用例都由官方文档翻译改编而来

1. 为什么需要Mock

测试驱动的开发( TDD)要求我们先写单元测试,再写实现代码。在写单元测试的过程中,我们往往会遇到要测试的类有很多依赖,这些依赖的类/对象/资源又有别的依赖,从而形成一个大的依赖树,要在单元测试的环境中完整地构建这样的依赖,是一件很困难的事情。如下图所示: 

为了测试类A,我们需要Mock B类和C类(用虚拟对象来代替)如下图所示:

2. mock和Mockito的关系

在软件开发中提及”mock”,通常理解为模拟对象
为什么需要模拟? 在我们一开始学编程时,我们所写的对象通常都是独立的,并不依赖其他的类,也不会操作别的类。但实际上,软件中是充满依赖关系的,比如我们会基于service类写操作类,而service类又是基于数据访问类(DAO)的,依次下去,形成复杂的依赖关系。

单元测试的思路就是我们想在不涉及依赖关系的情况下测试代码。这种测试可以让你无视代码的依赖关系去测试代码的有效性。核心思想就是如果代码按设计正常工作,并且依赖关系也正常,那么他们应该会同时工作正常。

有些时候,我们代码所需要的依赖可能尚未开发完成,甚至还不存在,那如何让我们的开发进行下去呢?使用mock可以让开发进行下去,mock技术的目的和作用就是模拟一些在应用中不容易构造或者比较复杂的对象,从而把测试与测试边界以外的对象隔离开。

我们可以自己编写自定义的Mock对象实现mock技术,但是编写自定义的Mock对象需要额外的编码工作,同时也可能引入错误。现在实现mock技术的优秀开源框架有很多,Mockito就是一个优秀的用于单元测试的mock框架。Mockito已经在github上开源,详细请点击:https://github.com/mockito/mockito

除了Mockitob已被广泛使用以外,还有一些类似的框架,比如:

  • EasyMock:早期比较流行的MocK测试框架。它提供对接口的模拟,能够通过录制、回放、检查三步来完成大体的测试过程,可以验证方法的调用种类、次数、顺序,可以令 Mock 对象返回指定的值或抛出指定异常
  • PowerMock:这个工具是在EasyMock和Mockito上扩展出来的,目的是为了解决EasyMock和Mockito不能解决的问题,比如对static, final, private方法均不能mock。其实测试架构设计良好的代码,一般并不需要这些功能,但如果是在已有项目上增加单元测试,老代码有问题且不能改时,就不得不使用这些功能了
  • JMockit:JMockit 是一个轻量级的mock框架是用以帮助开发人员编写测试程序的一组工具和API,该项目完全基于 Java 5 SE 的 java.lang.instrument 包开发,内部使用 ASM 库来修改Java的Bytecode

二、添加依赖

Mockitod 的maven依赖

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.8.47</version>
</dependency>

Mockitod 通常会结合junit使用

<dependency>
  <groupId>org.junit</groupId>
  <artifactId>com.springsource.org.junit</artifactId>
  <version>4.8.2</version>
</dependency>

lombok 依赖,方便实现构造方法和get/set方法

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.8</version>
</dependency>
< dependency>
  < groupId> org.springframework.boot </ groupId>
  < artifactId> spring-boot-starter-test </ artifactId>
  < scope> test </ scope>
</ dependency>

在 SpringBoot 单元测试中使用 Mockito,引入spring-boot-starter-test 依赖,该依赖内就有包含了 JUnit、Mockito。

< dependency>
  < groupId> org.springframework.boot </ groupId>
  < artifactId> spring-boot-starter-test </ artifactId>
  < scope> test </ scope>
</ dependency>

在测试类中导入Mockito类方便使用Mockito类的静态方法

import static org.mockito.Mockito.*;

三、初始化mock对象

Mocmokito底层本质是对被mock动态代理,拦截方法调用,改变方法行为,比如返回预期结果
mockito 定义的注解主要有三个:

  • @Mock
    • 默认不执行,有返回值的,默认返回null
    • 定义了mock方法的执行mock(即虚假函数);
  • @Spy
    • 默认会调用真实的方法,有返回值的调用真实方法并返回真实值;
    • 定义了mock方法的执行mock(即虚假函数);
    • 可以verify验证
  • @InjectMocks
    • 用于自动注入@Spy和@Mock标注的对象,如:MyService 依赖 MyMockMapper、MySpyMapper,则会自动注入对应bean
    • 创建实体对象,只能对类注解,不能注解接口
    • 不支持verify验证

3.1 使用静态方法创建

Mocmokito使用cglib动态代理代理要模拟的类,调用静态方法Mockito.mock()传入类对象即可

// mock
Iterator iterator = mock(Iterator.class);

// spy
List<String> mockedList1 = spy(MyList.class);
// spy 重载
List<String> mockedList2 = spy(new MyList());

3.2 使用注解创建

使用注解创建模拟类更加简单,可读性好。
唯一需要注意的是,需要在@Before中调用MockitoAnnotations.initMocks(this);

public class ArticleManagerTest {

    @Mock 
    private ArticleCalculator calculator;
    @Spy 
    private ArticleDatabase database;    
    @Spy
    @InjectMock  
    private UserProvider userProvider;

	@Before
    public void init(){
        // 初始化带有mock注解的对象 @Mock,@Spy,@Captor,@InjectMocks
        MockitoAnnotations.initMocks(this);
    }
}

除了调用MockitoAnnotations.initMocks(this)方法外,还可以给类加上mock启动注解来实现,更多说明详见:MockitoJUnitRunner类

@RunWith(MockitoJUnitRunner.class)
public class MockitoExample {
	@Mock
	HashMap<String, Integer> hashMap;

	@Captor
	ArgumentCaptor<String> keyCaptor;

	@Captor
	ArgumentCaptor<Integer> valueCaptor;

	@Test
	public void saveTest() {
        hashMap.put("id", 100);
    }
}

3.3 Spring 注解

spring 定义的注解主要有两个,@MockBean 和 @SpyBean 生成的对象受spring管理,相当于自动替换对应类型bean的注入,依赖这些bean的上层bean会自动注入 mockBean/spyBean。

@Component
public class ExampleTest {
    
    @Autowired
    private MyService myService;
    
    @MockBean
    MyMockMapper myMockMapper;
    
    @SpyBean
    MySpyMapper mySpyMapper;

    @Test
    public void shouldDoSomething() {
        list.add(100);
    }
 }

3.4 mock常用方法

方法名 描述
Mockito.mock(classToMock) 模拟对象
Mockito.mock(classToMock,defaultAnswer) 使用默认Answer模拟对象
Mockito.spy(Object) 用spy监控真实对象,设置真实对象行为
Mockito.verify(mock) 验证行为是否发生
Mockito.when(methodCall).thenReturn(value1).thenReturn(value2) 触发时第一次返回value1,第n次都返回value2
Mockito.when(methodCall).thenReturn(value) 参数匹配
Mockito.doReturn(toBeReturned).when(mock).[method] 参数匹配(直接执行不判断)
Mockito.when(methodCall).thenAnswer(answer)) 预期回调接口生成期望值
Mockito.doThrow(toBeThrown).when(mock).[method] 模拟抛出异常。
Mockito.doAnswer(answer).when(methodCall).[method] 预期回调接口生成期望值(直接执行不判断)
Mockito.doNothing().when(mock).[method] 不做任何返回
Mockito.doCallRealMethod().when(mock).[method] 调用真实的方法
Mockito.when(mock.[method] ).thenCallRealMethod()
reset(mock) 重置mock

四、mock 方法(预返回存根)

4.1 thenReturn

当使用任何整数值调用 mockedList 的 get 方法时,依次i返回first、last。

LinkedList mockedList = mock(LinkedList.class);

// mock方法,保存存根, Mockito.anyInt 
when(mockedList.get(Mockito.anyInt)).thenReturn("first", "last");


// 第一次调用返回first
System.out.println(mockedList.get(1));
// 第二次调用返回last
System.out.println(mockedList.get(10));

限制只有当参数的数字是 3 时,才会回传字字符串 “hello” 。

LinkedList mockedList = mock(LinkedList.class);

// mock方法,保存存根, Mockito.anyInt 
when(mockedList.get(3)).thenReturn("hello");


// 调用返回 hello
System.out.pringln(mockedList.get(3));

当调用 mockedList 的 add 方法时,不管传进来的 String 是什么,都回传 100。

LinkedList mockedList = mock(LinkedList.class);

// mock方法,保存存根, Mockito.anyInt 
when(mockedList.add(Mockito.any(String.class)))).thenReturn(100);


// 调用返回 hello
System.out.pringln(mockedList.add("hello"));

4.2 thenThrow

模拟抛出异常


LinkedList mockedList = mock(LinkedList.class);

//保存存根, 设置异常
when(mockedList.get(1)).thenThrow(new RuntimeException());

//抛出异常
System.out.println(mockedList.get(1));

4.3 doNothing

模拟不返回

LinkedList mockedList = mock(LinkedList.class);

// get 方法不返回
Mockito.doNothing().when(mockedList).get();

五 verify 调用验证

5.1 验证调用次数

mock过的类,可以获取被调用的数据

LinkedList mockedList = mock(LinkedList.class);

//using mock, 分别调用1、2、3
mockedList.add("once");

mockedList.add("twice");
mockedList.add("twice");

mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");


// 没有调用过任何函数
verifyZeroInteractions(mockedList);

// 没有调用过指定函数
verify(mockedList, times(0)).size();
verify(mockedList, never()).clear();

// 调用过指定函数
verify(mockedList).add("once");
verify(mockedList).add("twice");

// 调用一次
verify(mockedList, times(1)).add("once");

// 调用二次
verify(mockedList, times(2)).add("twice");

// 调用三次
verify(mockedList, times(3)).add("three times");

// 没调用过
verify(mockedList, never()).add("never happened");

// 最少和最多调用次数
verify(mockedList, atLeastOnce()).add("three times");
// 最少调用两次
verify(mockedList, atLeast(2)).add("three times");
// 最多调用次数
verify(mockedList, atMost(5)).add("three times");

5.2 调用顺序验证

List<String> mockedList = mock(MyList.class);
// 执行方法
mockedList.size();
mockedList.add("a parameter");
mockedList.clear();

// 验证调用顺序
InOrder inOrder = Mockito.inOrder(mockedList);
inOrder.verify(mockedList).size();
inOrder.verify(mockedList).add("a parameter");
inOrder.verify(mockedList).clear();

六、ArgumentCaptor 参数捕获

捕获测试期间函数被调用时传入的参数,比如测试A函数,经过一些列的计算后A调用了B,此时我们可以捕获B的入参,验证A的计算逻辑是否正确

  • ArgumentCaptor.getValue(),返回最近一次参数
  • ArgumentCaptor.getAllValues�(),返回所有参数

我们可以使用assertEquals(expected, result)来验证参数是否符合预期。

@Test
public void argumentCaptorTest() {
    MyList myList = mock(MyList.class);
    myList.setName("test");

    ArgumentCaptor<String> capturedArgument = ArgumentCaptor.forClass(String.class);
    Mockito.verify(myList).setName(capturedArgument.capture());

    Assert.assertEquals("test", capturedArgument.getValue());
}

七. 参数模拟器

mockito还提供迭代器存根和回调存根,不常用,感兴趣可以看官方文档

如果使用参数匹配器,则所有参数都必须由匹配器提供。例如:(示例显示了验证,但对存根也是如此):

返回值 方法 描述
static <T> T [**any**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#any())()
匹配任何内容,包括null和varargs。
static <T> T [**any**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#any(java.lang.Class))([Class](https://docs.oracle.com/javase/6/docs/api/java/lang/Class.html?is-external=true)<T> type)
匹配任何给定类型的对象,不包括null。 模拟数组 any(byte[].class),其他类型同理
static boolean [**anyBoolean**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyBoolean())()
任何boolean非空 Boolean
static byte [**anyByte**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyByte())()
任何byte或者非空 Byte
static char [**anyChar**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyChar())()
任何char或者非空 Character
static <T> [Collection](https://docs.oracle.com/javase/6/docs/api/java/util/Collection.html?is-external=true)<T> [**anyCollection**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyCollection())()
任何非null Collection
static double [**anyDouble**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyDouble())()
任何double或者非空 Double
static float [**anyFloat**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyFloat())()
任何float或者非空 Float
static int [**anyInt**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyInt())()
任何int或non-null Integer
static <T> [Iterable](https://docs.oracle.com/javase/6/docs/api/java/lang/Iterable.html?is-external=true)<T> [**anyIterable**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyIterable())()
任何非null Iterable
static <T> [List](https://docs.oracle.com/javase/6/docs/api/java/util/List.html?is-external=true)<T> [**anyList**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyList())()
任何非null List
static long [**anyLong**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyLong())()
任何long或者非空 Long
static <K,V> [Map](https://docs.oracle.com/javase/6/docs/api/java/util/Map.html?is-external=true)<K,V> [**anyMap**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyMap())()
任何非null Map
static <T> T [**anyObject**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyObject())()
不推荐使用。
这将在Mockito 3.0中删除(仅适用于Java 8)
static <T> [Set](https://docs.oracle.com/javase/6/docs/api/java/util/Set.html?is-external=true)<T> [**anySet**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anySet())()
任何非null Set
static short [**anyShort**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyShort())()
任何short或者非空 Short
static [String](https://docs.oracle.com/javase/6/docs/api/java/lang/String.html?is-external=true) [**anyString**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyString())()
任何非空 String
static <T> T [**anyVararg**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyVararg())()
不推荐使用。
_从2.1.0开始使用 _[_any()_](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#any())

八、使用案例

verify 验证行为是否发生

//模拟创建一个List对象
List<Integer> mock =  Mockito.mock(List.class);
//调用mock对象的方法
mock.add(1);
mock.clear();
//验证方法是否执行
Mockito.verify(mock).add(1);
Mockito.verify(mock).clear();

verify 多次触发返回不同值

//mock一个Iterator类
Iterator iterator = mock(Iterator.class);
//预设当iterator调用next()时第一次返回hello,第n次都返回world
Mockito.when(iterator.next()).thenReturn("hello").thenReturn("world");
//使用mock的对象
String result = iterator.next() + " " + iterator.next() + " " + iterator.next();
//验证结果
Assert.assertEquals("hello world world",result);

doThrow 模拟抛出异常

@Test(expected = IOException.class)//期望报IO异常
public void when_thenThrow() throws IOException{
      OutputStream mock = Mockito.mock(OutputStream.class);
      //预设当流关闭时抛出异常
      Mockito.doThrow(new IOException()).when(mock).close();
      mock.close();
  }

Answer 模拟对象

return只能提供固定的返回值,而answer可以提供更复杂的计算逻辑。
RETURNS_DEEP_STUBS 是创建mock对象时的备选参数之一,以下方法deepstubsTestdeepstubsTest2是等价的


@Test
  public void deepstubsTest(){
      A a = Mockito.mock(A.class,Mockito.RETURNS_DEEP_STUBS);
      Mockito.when(a.getB().getName()).thenReturn("Beijing");
      Assert.assertEquals("Beijing",a.getB().getName());
  }

  @Test
  public void deepstubsTest2(){
      A a=Mockito.mock(A.class);
      B b=Mockito.mock(B.class);
      Mockito.when(a.getB()).thenReturn(b);
      Mockito.when(b.getName()).thenReturn("Beijing");
      Assert.assertEquals("Beijing",a.getB().getName());
  }

  class A{
      private B b;
      public B getB(){
          return b;
      }
      public void setB(B b){
          this.b=b;
      }
  }

  class B{
      private String name;
      public String getName(){
          return name;
      }
      public void setName(String name){
          this.name = name;
      }
      public String getSex(Integer sex){
          if(sex==1){
              return "man";
          }else{
              return "woman";
          }
      }
  }

Answer 预期回调接口生成期望值

@Test
public void answerTest(){
      List mockList = Mockito.mock(List.class);
      //使用方法预期回调接口生成期望值(Answer结构)
      Mockito.when(mockList.get(Mockito.anyInt())).thenAnswer(new CustomAnswer());
      Assert.assertEquals("hello world:0",mockList.get(0));
      Assert.assertEquals("hello world:999",mockList.get(999));
  }
  private class CustomAnswer implements Answer<String> {
      @Override
      public String answer(InvocationOnMock invocation) throws Throwable {
          Object[] args = invocation.getArguments();
          return "hello world:"+args[0];
      }
  }
等价于:(也可使用匿名内部类实现)
@Test
 public void answer_with_callback(){
      //使用Answer来生成我们我们期望的返回
      Mockito.when(mockList.get(Mockito.anyInt())).thenAnswer(new Answer<Object>() {
          @Override
          public Object answer(InvocationOnMock invocation) throws Throwable {
              Object[] args = invocation.getArguments();
              return "hello world:"+args[0];
          }
      });
      Assert.assertEquals("hello world:0",mockList.get(0));
     Assert. assertEquals("hello world:999",mockList.get(999));
  }

Answer - 修改对未预设的调用返回默认期望(指定返回值)

//mock对象使用Answer来对未预设的调用返回默认期望值
List mock = Mockito.mock(List.class,new Answer() {
     @Override
     public Object answer(InvocationOnMock invocation) throws Throwable {
         return 999;
     }
 });
 //下面的get(1)没有预设,通常情况下会返回NULL,但是使用了Answer改变了默认期望值
 Assert.assertEquals(999, mock.get(1));
 //下面的size()没有预设,通常情况下会返回0,但是使用了Answer改变了默认期望值
 Assert.assertEquals(999,mock.size());

doAnswer 预期回调接口生成期望值(直接执行)

@Test
public void testAnswer1(){
List<String> mock = Mockito.mock(List.class);  
      Mockito.doAnswer(new CustomAnswer()).when(mock).get(Mockito.anyInt());  
      Assert.assertEquals("大于三", mock.get(4));
      Assert.assertEquals("小于三", mock.get(2));
}
public class CustomAnswer implements Answer<String> {  
  public String answer(InvocationOnMock invocation) throws Throwable {  
      Object[] args = invocation.getArguments();  
      Integer num = (Integer)args[0];  
      if( num>3 ){  
          return "大于三";  
      } else {  
          return "小于三";   
      }  
  }
}

when 参数匹配

@Test
public void with_arguments(){
    B b = Mockito.mock(B.class);
    //预设根据不同的参数返回不同的结果
    Mockito.when(b.getSex(1)).thenReturn("男");
    Mockito.when(b.getSex(2)).thenReturn("女");
    Assert.assertEquals("男", b.getSex(1));
    Assert.assertEquals("女", b.getSex(2));
    //对于没有预设的情况会返回默认值
    Assert.assertEquals(null, b.getSex(0));
}
class B{
    private String name;
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getSex(Integer sex){
        if(sex==1){
            return "man";
        }else{
            return "woman";
        }
    }
}

when 匹配任意参数

  • Mockito.anyInt() 任何 int 值 ;
  • Mockito.anyLong() 任何 long 值 ;
  • Mockito.anyString() 任何 String 值 ;
  • Mockito.any(XXX.class) 任何 XXX 类型的值 等等。
@Test
public void with_unspecified_arguments(){
    List list = Mockito.mock(List.class);
    //匹配任意参数
    Mockito.when(list.get(Mockito.anyInt())).thenReturn(1);
    Mockito.when(list.contains(Mockito.argThat(new IsValid()))).thenReturn(true);
    Assert.assertEquals(1,list.get(1));
    Assert.assertEquals(1,list.get(999));
    Assert.assertTrue(list.contains(1));
    Assert.assertTrue(!list.contains(3));
}
class IsValid extends ArgumentMatcher<List>{
    @Override
    public boolean matches(Object obj) {
        return obj.equals(1) || obj.equals(2);
    }
}

注意:使用了参数匹配,那么所有的参数都必须通过matchers来匹配

Mockito继承Matchers,anyInt()等均为Matchers方法
当传入两个参数,其中一个参数采用任意参数时,指定参数需要matchers来对比

Comparator comparator = mock(Comparator.class);
comparator.compare("nihao","hello");
//如果你使用了参数匹配,那么所有的参数都必须通过matchers来匹配
Mockito.verify(comparator).compare(Mockito.anyString(),Mockito.eq("hello"));
//下面的为无效的参数匹配使用
//verify(comparator).compare(anyString(),"hello");

when 自定义参数匹配

@Test
public void argumentMatchersTest(){
   //创建mock对象
   List<String> mock = mock(List.class);
   //argThat(Matches<T> matcher)方法用来应用自定义的规则,可以传入任何实现Matcher接口的实现类。
   Mockito.when(mock.addAll(Mockito.argThat(new IsListofTwoElements()))).thenReturn(true);
   Assert.assertTrue(mock.addAll(Arrays.asList("one","two","three")));
}

class IsListofTwoElements extends ArgumentMatcher<List>
{
   public boolean matches(Object list)
   {
       return((List)list).size()==3;
   }
}

spy 监控真实对象,设置真实对象行为

    @Test(expected = IndexOutOfBoundsException.class)
    public void spy_on_real_objects(){
        List list = new LinkedList();
        List spy = Mockito.spy(list);
        //下面预设的spy.get(0)会报错,因为会调用真实对象的get(0),所以会抛出越界异常
        //Mockito.when(spy.get(0)).thenReturn(3);

        //使用doReturn-when可以避免when-thenReturn调用真实对象api
        Mockito.doReturn(999).when(spy).get(999);
        //预设size()期望值
        Mockito.when(spy.size()).thenReturn(100);
        //调用真实对象的api
        spy.add(1);
        spy.add(2);
        Assert.assertEquals(100,spy.size());
        Assert.assertEquals(1,spy.get(0));
        Assert.assertEquals(2,spy.get(1));
        Assert.assertEquals(999,spy.get(999));
    }

doNothing 不做任何返回

@Test
public void Test() {
    A a = Mockito.mock(A.class);
    //void 方法才能调用doNothing()
    Mockito.doNothing().when(a).setName(Mockito.anyString());
    a.setName("bb");
    Assert.assertEquals("bb",a.getName());
}
class A {
    private String name;
    private void setName(String name){
        this.name = name;
    }
    private String getName(){
        return name;
    }
}

doCallRealMethod 调用真实的方法

@Test
public void Test() {
    A a = Mockito.mock(A.class);
    //void 方法才能调用doNothing()
    Mockito.when(a.getName()).thenReturn("bb");
    Assert.assertEquals("bb",a.getName());
    //等价于Mockito.when(a.getName()).thenCallRealMethod();
    Mockito.doCallRealMethod().when(a).getName();
    Assert.assertEquals("zhangsan",a.getName());
}
class A {
    public String getName(){
        return "zhangsan";
    }
}

重置 mock

    @Test
    public void reset_mock(){
        List list = mock(List.class);
        Mockito. when(list.size()).thenReturn(10);
        list.add(1);
        Assert.assertEquals(10,list.size());
        //重置mock,清除所有的互动和预设
        Mockito.reset(list);
        Assert.assertEquals(0,list.size());
    }

@Mock 注解

public class MockitoTest {
    @Mock
    private List mockList;
    //必须在基类中添加初始化mock的代码,否则报错mock的对象为NULL
    public MockitoTest(){
        MockitoAnnotations.initMocks(this);
    }
    @Test
    public void AnnoTest() {
            mockList.add(1);
        Mockito.verify(mockList).add(1);
    }
}

指定测试类使用运行器:MockitoJUnitRunner

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest2 {
    @Mock
    private List mockList;

    @Test
    public void shorthand(){
        mockList.add(1);
        Mockito.verify(mockList).add(1);
    }
}


参考材料

posted @   喜欢嗑瓜子  阅读(1185)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示