java – Mockito – “想要但不被调用;但是还有其他与这个模拟的交互“错误

我验证一个函数是使用Mockito调用的,但是Mockito告诉我,我正在验证的函数从来没有被调用,而其他函数调用.但是在我看来,我正在调用正确的功能

这是我遇到的错误的堆栈跟踪:

Wanted but not invoked:
relationshipAutoIndexer.getAutoIndex();
-> at org.whispercomm.manes.server.graph.DataServiceImplTest.testInitIndices(DataServiceImplTest.java:117)

However,there were other interactions with this mock:
-> at org.whispercomm.manes.server.graph.DataServiceImpl.updateIndexProperties(DataServiceImpl.java:136)
-> at org.whispercomm.manes.server.graph.DataServiceImpl.updateIndexProperties(DataServiceImpl.java:144)
-> at org.whispercomm.manes.server.graph.DataServiceImpl.updateIndexProperties(DataServiceImpl.java:148)
-> at org.whispercomm.manes.server.graph.DataServiceImpl.updateIndexProperties(DataServiceImpl.java:149)
-> at org.whispercomm.manes.server.graph.DataServiceImpl.initIndices(DataServiceImpl.java:121)

    at org.whispercomm.manes.server.graph.DataServiceImplTest.testInitIndices(DataServiceImplTest.java:117)

它发生在

verify(relAutoIndexer).getAutoIndex();

的测试类代码如下所示.

这是我的代码(我有一个倾向,意外的事情,请问我的任何代码,你认为我失踪,我会添加):

public DataServiceImpl(GraphDatabaseService graphDb) {
    super();
    this.graphDb = graphDb;
    unarchivedParent = new UnarchivedParent(graphDb.createNode());
    archivedParent = new ArchivedParent(graphDb.createNode());
    packetParent = new PacketParent(graphDb.createNode());
    userParent = new UserParent(graphDb.createNode());
    this.initIndices();
}

/**
 * Initializes the node and relationship indexes.
 * 
 * Updates the set of indexed properties to match {@link DataServiceImpl}
 * .NODE_KEYS_INDEXABLE and {@link DataServiceImpl}.REL_KEYS_INDEXABLE.
 * 
 * Note: auto indices can also be configured at database creation time and
 * just retrieved at runtime. We might want to switch to that later.
 */
private void initIndices() {
    /* Get the auto-indexers */
    AutoIndexer<Node> nodeAutoIndexer = this.graphDb.index()
            .getNodeAutoIndexer();

    AutoIndexer<Relationship> relAutoIndexer = this.graphDb.index()
            .getRelationshipAutoIndexer();

    this.updateIndexProperties(nodeAutoIndexer,DataServiceImpl.NODE_KEYS_INDEXABLE);

    this.nodeIndex = nodeAutoIndexer.getAutoIndex();

    this.updateIndexProperties(relAutoIndexer,DataServiceImpl.REL_KEYS_INDEXABLE);

    this.relIndex = relAutoIndexer.getAutoIndex();
}

/**
 * Sets the indexed properties of an {@link AutoIndexer} to the specified
 * set,removing old properties and adding new ones.
 * 
 * @param autoIndexer
 *            the AutoIndexer to update.
 * @param properties
 *            the properties to be indexed.
 * @return autoIndexer,this given AutoIndexer (useful for chaining calls.)
 */
private <T extends PropertyContainer> AutoIndexer<T> updateIndexProperties(
        AutoIndexer<T> autoIndexer,Set<String> properties) {
    Set<String> indexedProps = autoIndexer.getAutoIndexedProperties();
    // Remove unneeded properties.
    for (String prop : difference(indexedProps,properties)) {
        autoIndexer.stopAutoIndexingProperty(prop);
    }

    // Add new properties.
    for (String prop : difference(properties,indexedProps)) {
        autoIndexer.startAutoIndexingProperty(prop);
    }

    // Enable the index,if needed.
    if (!autoIndexer.isEnabled()) {
        autoIndexer.setEnabled(true);
    }

    return autoIndexer;
}

这里是测试类的代码

@Before
public void setup() {
   nA = mock(Node.class);
   nB = mock(Node.class);
   packetA = new PacketWrapper(nA);
   packetB = new PacketWrapper(nB);
   RelA = mock(Relationship.class);
   RelB = mock(Relationship.class);
   graphDb = mock(GraphDatabaseService.class);
   nodeAutoIndexer = (AutoIndexer<Node>) mock(AutoIndexer.class);
       relAutoIndexer = mock(RelationshipAutoIndexer.class);
}

@After
public void tearDown() {
  packetA = null;
  packetB = null;
}
/*
 * ---------------- Test initIndices() ---------------
 */
//TODO
@Test
public void testInitIndices() throws IllegalArgumentException,IllegalAccessException,InvocationTargetException,NoSuchMethodException {
   IndexManager indexManager = mock(IndexManager.class);
   when(graphDb.index()).thenReturn(indexManager);
   when(indexManager.getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
       when(graphDb.index().getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);
   dataService = new DataServiceImpl(graphDb);
       verify(nodeAutoIndexer,atLeastOnce()).getAutoIndex();
       verify(relAutoIndexer).getAutoIndex();                       
}

解决方法

Mockito,直到版本1.8.5,在多态发送的情况下有一个错误.它是固定的,可在版本1.9.0的第一个发行版中.见 issue 200.

那么在代码库中如何发生.注意你在嘲笑这两个类

nodeAutoIndexer = (AutoIndexer<Node>) mock(AutoIndexer.class);
relAutoIndexer = mock(RelationshipAutoIndexer.class);

AutoIndexer恰好是一个通用的父接口,在这个接口中有这个方法ReadableIndex< T> getAutoIndex(). RelationshipAutoIndexer是AutoInexer的一个子类型,其中通用部分被修改为Relationship,并覆盖getAutoIndex()方法以返回协变类型ReadableRelationshipIndex.

AutoIndexerRelationshipIndexer.

那么在你的通话代码中,你有以下几行:

AutoIndexer<Node> nodeAutoIndexer = this.graphDb.index().getNodeAutoIndexer();
AutoIndexer<Relationship> relAutoIndexer = this.graphDb.index().getRelationshipAutoIndexer();
this.nodeIndex = nodeAutoIndexer.getAutoIndex();
this.relIndex = relAutoIndexer.getAutoIndex();

您的生产代码中的nodeAutoIndex和测试代码中的mock nodeAutoIndexer都具有AutoIndexer&Node Node类型的引用,因此关于多态调度没有问题.
但是,您的生产代码中的relAutoIndex由AutoIndexer&Relationships类型引用.并且您的测试代码中的模拟relAutoIndexer由RelationshipAutoIndexer引用,因此错误的调​​用在模拟器上注册,然后验证失败.

您的解决方案是升级mockito版本; 1.9.0 RC1是非常稳定的,最后一个版本应该是你的方式.或者您可以从以下地址迁移参考类型(在生产代码中):

AutoIndexer<Relationship> relAutoIndexer = this.graphDb.index().getRelationshipAutoIndexer();

至 :

RelationshipAutoIndexer relAutoIndexer = this.graphDb.index().getRelationshipAutoIndexer();

另外几句话.

>你不需要在这里写一个after方法,因为JUnit在每个方法运行时创建一个新的实例,所以你的方法只是添加将要完成的代码.请注意,TestNG不是这样.
而不是在before方法中创建你的mocks,你可能想使用Mockito注释.不要忘记跑步者.

例如 :

@RunWith(MockitoJUnitRunner.class)
public class YourTest {
    @Mock SomeType someTypeMock;
    // ...
}

>由于几个原因,stubbing代码有点丑陋.

>你应该写一个一致的存根.

为什么不用清洁的方式写这个;例如在两种情况下引用indexManager:

IndexManager indexManager = mock(IndexManager.class);
when(graphDb.index()).thenReturn(indexManager);
when(indexManager.getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(indexManager.getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);

或者不要引用它

IndexManager indexManager = mock(IndexManager.class);
when(graphDb.index()).thenReturn(indexManager);
when(graphDb.index().getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(graphDb.index().getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);

还有一个模仿的模拟通常是设计气味的标志.你打破了德米特的法律,打破这意味着你会遇到困难的测试,可维护性差,难以进化.当我说你可以听到我耳语(没有三段话):它会花费你的钱.不要写遗留代码!如果您正在练习TDD或BDD,那么您将在设计时将自己的代码识别出这些问题,这样可以很好地防止这些问题.

>但是,如果您正在处理旧版代码,则可以使用此深层存根语法:

使用静态方法可以写这个

GraphDatabaseService graphdb = mock(GraphDatabaseService.class,RETURNS_DEEP_STUBS);

或者使用注释,你可以写这个:

@Mock(answer = RETURNS_DEEP_STUBS) GraphDatabaseService graphdb;

和桩:

when(graphDb.index().getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(graphDb.index().getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);

相关文章

ArrayList简介:ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增...
一、进程与线程 进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。 线程...
本文为博客园作者所写:&#160;一寸HUI,个人博客地址:https://www.cnblogs.com/zsql/ 简单的一个类...
#############java面向对象详解#############1、面向对象基本概念2、类与对象3、类和对象的定义格式4、...
一、什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错。在java中,阻止当前方法或作用域...
Collection接口 Collection接口 Collection接口 Collection是最基本的集合接口,一个Collection代表一组...