首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Mockito内部

Mockito内部
EN

Stack Overflow用户
提问于 2013-03-29 06:28:53
回答 1查看 2.8K关注 0票数 6

我在试着理解Mockito的内部是如何工作的。到目前为止,代码对我来说很难理解,我正在寻找一份关于Mockito基本工作原理的高级调查。

Mockito @ GrepCode

我已经写了一些示例代码来演示我目前的理解:

代码语言:javascript
复制
class C {
    String s;
    public void getS() { return s; }
    // ...
}

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

据我所知,'mock‘方法只看到cm.getS()的返回值。它如何知道方法的名称(以便将其存根)?另外,它如何知道传递给该方法的参数?

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

代码语言:javascript
复制
// org.mockito.Mockito
public static <T> OngoingStubbing<T> when(T methodCall) {
    return MOCKITO_CORE.when(methodCall);
}

我在几个不同的抽象、类和对象中跟踪了方法调用,但代码是如此分离,因此很难以这种方式理解。

代码语言:javascript
复制
//  org.mockito.internal.MockitoCore
public <T> OngoingStubbing<T> when(T methodCall) {
    mockingProgress.stubbingStarted();
    return (OngoingStubbing) stub();
}

因此,如果任何人了解内部原理或有讨论/博客帖子的链接,请分享:)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-03-29 14:31:21

(抱歉,这篇文章太长了。TL;DR: Mockito记录了幕后的方法调用。)

代码语言:javascript
复制
C cm = mock(C.class);

在这一点上,您可能认为cmC...and的一个实例,您就错了。相反,cmproxy object Mockito写入的一个实例,它实现了C (因此可以分配给C类型的字段/变量),但是记录了您所请求的所有内容,并按照您存根的方式进行操作。

让我们编写一个模拟类manually...and,再给它一个方法,比方说int add(int a, int b),它在实际类中添加ab

代码语言:javascript
复制
class MockC extends C {
  int returnValue;

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

那里!现在,无论何时调用add,它都不会将两个数字相加,而只是返回单个返回值。合乎道理。但是,如果您想要稍后验证这些调用,该怎么办?

代码语言:javascript
复制
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使用自动生成一个,它的行为类似于MockC,将所有的交互和返回值保存在一个大的静态列表中。这个列表被称为RegisteredInvocations,每个mock的每个方法调用都是一个Invocation,而不是Object[],但思想是相同的。

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

这就解决了大部分问题,除了像eqany这样的参数匹配器:原来这些只是kept on a fancy stack,称为ArgumentMatcherStoragewhen调用checks how many matchers are on the stack:对于add示例,零匹配器告诉Mockito推断每个记录的参数是否相等,两个匹配器告诉Mockito从堆栈中弹出这些参数并使用它们。只有一个匹配器意味着Mockito不知道你想要匹配的是哪个整数,并抛出经常令人困惑的InvalidUseOfMatchersException,这就是为什么在使用匹配器时,如果你匹配任何参数,就需要匹配每个参数。

希望这能有所帮助!

编辑: This answer更详细地描述了when方法是如何工作的。

票数 19
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15693283

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档