6

我试图了解 Mockito 的内部结构如何运作。到目前为止,代码对我来说很难理解,我正在寻找对 Mockito 基本工作原理的高级调查。

模拟@GrepCode

我编写了一些示例代码来展示我目前的理解:

class C {
    String s;
    public void getS() { return s; }
    // ...
}

C cm = mock( C.class);
when( cm.method() ).thenReturn( "string value");

据我所知,“模拟”方法只看到 cm.getS() 的返回值。它如何知道方法的名称是什么(以便存根)?此外,它如何知道传递给该方法的参数?

mockito API 方法调用内部对象的方法:

// org.mockito.Mockito
public static <T> OngoingStubbing<T> when(T methodCall) {
    return MOCKITO_CORE.when(methodCall);
}

我已经将方法调用跟踪到了几个不同的抽象以及类和对象中,但是代码是如此解耦,以至于很难理解这种方式。

//  org.mockito.internal.MockitoCore
public <T> OngoingStubbing<T> when(T methodCall) {
    mockingProgress.stubbingStarted();
    return (OngoingStubbing) stub();
}

因此,如果有人了解内部结构或有讨论/博客文章的链接,请分享:)

4

1 回答 1

19

(对不起,这很长。TL;DR:Mockito 记录了幕后的方法调用。)

C cm = mock(C.class);

在这一点上,你可能会认为这cmC……的一个例子,你就错了。相反,cm它是一个代理对象 Mockito的实例,它实现C(因此可以分配给 C 类型的字段/变量)但记录您要求的所有内容并按照您存根的方式运行。

让我们手动编写一个模拟类......并再给它一个方法,比如说,它在实际类int add(int a, int b)中添加aand 。b

class MockC extends C {
  int returnValue;

  @Override int add(int a, int b) {
    return returnValue;
  }
}

那里!现在,无论何时调用add,它都不会添加两个数字,而是只返回单个返回值。说得通。但是,如果您想稍后验证调用怎么办?

class MockC extends C {
  List<Object[]> parameterValues = new ArrayList<>();
  int returnValue;

  @Override int add(int a, int b) {
    parameterValues.add(new Object[] { a, b });
    return returnValue;
  }
}

所以现在您可以检查parameterValues列表并确保它按预期调用。

事情是这样的: Mockito使用CGLIB生成一个代理,它自动像 MockC 一样工作,将所有交互和返回值保存在一个大的静态列表中。该列表被称为RegisteredInvocations,而不是Object[]每个模拟的每个方法调用都是一个Invocation,但想法是相同的。

要了解更多关于它所公开RegisteredInvocations的方法以及为什么removeLast如此重要的信息,请阅读InvocationContainer. 因为 Mockito 记录了每一个调用,它自然会记录其中包含的交互when。一旦 Mockito 看到when,它就会删除最后记录的交互InvocationContainerImpl.java第 45 行)并将其用作存根的模板——从 Invocation 对象本身读取参数值。

这可以解决大部分问题,除了参数匹配器eqany: 结果这些只是保存在一个名为ArgumentMatcherStorage. 该when调用检查堆栈上有多少匹配器add例如,零匹配器告诉 Mockito 推断与每个记录的参数相等,两个匹配器告诉 Mockito 将它们从堆栈中弹出并使用它们。只有一个匹配器意味着 Mockito 无法判断您要匹配哪个整数并抛出经常令人困惑的InvalidUseOfMatchersException,这就是为什么在使用匹配器时,如果您匹配任何参数,则需要匹配每个参数。

希望有帮助!

编辑: 这个答案描述了该when方法如何在更多技术细节上工作。

于 2013-03-29T06:31:20.930 回答