Unit testing 莫基托堆内构件

Unit testing 莫基托堆内构件,unit-testing,testing,mocking,mockito,internals,Unit Testing,Testing,Mocking,Mockito,Internals,我试图理解Mockito的内部功能。到目前为止,代码对我来说很难理解,我正在寻找对Mockito基本工作原理的高级调查 我已经编写了一些示例代码来演示我目前的理解: C类{ 字符串s; public void get(){return s;} // ... } C cm=模拟(C类); 当(cm.method())。然后返回(“字符串值”); 据我所知,“mock”方法只看到cm.get()的返回值。它如何知道方法的名称(以便存根)?另外,它如何知道传递给方法的参数 mockito API方

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

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

C类{
字符串s;
public void get(){return s;}
// ...
}
C cm=模拟(C类);
当(cm.method())。然后返回(“字符串值”);
据我所知,“mock”方法只看到cm.get()的返回值。它如何知道方法的名称(以便存根)?另外,它如何知道传递给方法的参数

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

//org.mockito.mockito
公共静态ONGOINGSTUBING时(T方法调用){
返回MOCKITO_CORE.when(methodCall);
}
我已经跟随方法调用进入了几个不同的抽象、类和对象中,但是代码是如此的解耦以至于很难用这种方式理解

//org.mockito.internal.MockitoCore
公共ONGOINGSTUBING时(T方法调用){
mockingProgress.stubbingStarted();
返回(ongoingstubing)存根();
}
因此,如果有人了解内部结构或有讨论/博客帖子的链接,请共享:)

(很抱歉,这太长了。TL;DR:Mockito在幕后记录方法调用。)

此时,您可能会认为
cm
C
的一个实例,您可能会错。相反,
cm
Mockito
写入的一个实例,它实现了
C
(因此可以分配给C类型的字段/变量),但记录您请求的所有内容,并以存根的方式进行操作

让我们手动编写一个模拟类…并给它多一个方法,比如说
intadd(inta,intb)
,它在实际类中添加
a
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;
  }
}
类MockC扩展了C{
List parameterValues=new ArrayList();
返回值;
@覆盖整数添加(整数a、整数b){
add(新对象[]{a,b});
返回值;
}
}
因此,现在您可以检查
参数值
列表,并确保按预期调用它

事情是这样的:Mockito生成一个类似MockC的using,将所有交互和返回值保存在一个大的静态列表中。调用列表,而不是
对象[]
每个mock的每个方法调用都是一个,但思想是一样的

要进一步了解
RegisteredInvestations
以及它公开的
removeLast
方法为何如此重要,请阅读中的代码。因为Mockito记录每个调用,所以当时,它自然会记录
中包含的交互。Mockito在
时一看到
,就会删除最后记录的交互(第45行),并将其用作存根的模板——从调用对象本身读取参数值

除了像
eq
any
这样的参数匹配器之外,这就解决了大部分问题:事实证明,它们只是被调用了。
when
调用:对于
add
示例,零匹配器告诉Mockito推断每个记录参数的相等性,两个匹配器告诉Mockito将这些参数从堆栈中弹出并使用它们。只有一个匹配器意味着Mockito无法判断要匹配的整数,并抛出经常令人困惑的结果,这就是为什么在使用匹配器时,如果匹配任何参数,就需要匹配每个参数

希望有帮助

EDIT:详细介绍了
方法在
时的工作原理

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;
  }
}