# mockito

# 常用静态方法

thenReturn
thenAnswer
thenThrow

doReturn
doThrow
doAnswer

MockedConstruction<T>
MockedStatic<T>
1
2
3
4
5
6
7
8
9
10

# mock静态方法

264573415240653.png

# @Mock与@Spy

spy可打桩方法内部的公共方法

524213615259079.png

# mock方法内部new出来的对象

参考mock静态方法

# mock有参构造函数

但是在这个用例中,在处理一个对象时,需要每次生成对象,都让这个对象的某个方法的表现是被替代的。 这个时候很多人会想到:

Person person = Mockito.spy(Person.class);
PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);
Mockito.when(person.say()).thenReturn("mock for say.");
1
2
3

然后就可以只对每个Person对象的say方法进行mock,而其他方法执行实际代码逻辑。

接下来,尝试仅使用Mockito的方式进行这个实践

首先观察Mockito的方法,有两个方法名与构造函数有关:mockConstructionmockConstructionWithAnswer

接下来尝试mockConstruction,发现如何mock,都无法实现上面的效果,没有被Mockito.when的方法默认是doNothing策略,导致无法达成测试用例的目的

Mockito.mockConstruction(Person.class, (person, context) -> {
      // 各种mock尝试
});
1
2
3

那么只能用mockConstructionWithAnswer继续进行尝试, 方法签名:

public static <T> MockedConstruction<T> mockConstructionWithAnswer(
            Class<T> classToMock, Answer defaultAnswer, Answer... additionalAnswers) {
        return mockConstruction(
                classToMock,
                context -> {
                    if (context.getCount() == 1 || additionalAnswers.length == 0) {
                        return withSettings().defaultAnswer(defaultAnswer);
                    } else if (context.getCount() >= additionalAnswers.length) {
                        return withSettings()
                                .defaultAnswer(additionalAnswers[additionalAnswers.length - 1]);
                    } else {
                        return withSettings()
                                .defaultAnswer(additionalAnswers[context.getCount() - 2]);
                    }
                },
                (mock, context) -> {});
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

观察方法签名,显然需要我们实现一个answer进行传入,通过观察,invocation对象拥有方法的对象,以及方法的对应入参,那么可以使用类反射的机制直接突破困境,如下面的代码

Person person = Mockito.spy(Person.class);
Mockito.when(person.say()).thenReturn("mock for say.");
Mockito.mockConstructionWithAnswer(Person.class, new Answer() {
     @Override
     public Object answer(InvocationOnMock invocation) throws Throwable {
         return invocation.getMethod().invoke(person, invocation.getArguments());
     }
});
1
2
3
4
5
6
7
8