Java – mockito – “wanted but not called; but there are other interaction errors with this simulation”

I verified that a function was called using mockito, but mockito told me that the function I was verifying had never been called, while other functions were called But in my opinion, I'm calling the right function

This is the stack trace of the error I encountered:

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)

It happened in

verify(relAutoIndexer).getAutoIndex();

The test class code of is as follows

This is my code (I have a tendency, unexpected things, ask any of my code, you think I'm missing, I'll add):

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

Here is the code of the test class:

@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();                       
}

Solution

Mockito until version 1.8 5. There is an error in the case of polymorphic transmission It is fixed and available in version 1.9 In the first release of 0 See issue 200

So how does it happen in the code base Notice that you're laughing at these two classes

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

AutoIndexer happens to be a general parent interface, in which the method readableindex < T > getautoindex() Relationshipautoindexer is a subtype of AutoIndexer, where the common part is modified to relationship and overrides the getautoindex () method to return the covariant type readablerelationshipindex

See AutoIndexer and relationshipindexer

Then in your call code, you have the following lines:

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

Both nodeautoindex in your production code and mock nodeautoindexer in your test code have references of AutoIndexer & node type, so there is no problem with polymorphic scheduling However, the relautoindex in your production code is referenced by the AutoIndexer & Relationships type And the simulated relautoindexer in your test code is referenced by relationshipautoindexer, so the wrong call is registered on the simulator, and then the verification fails

Your solution is to upgrade the mockito version; 1.9. 0 RC1 is very stable. The last version should be your way Alternatively, you can migrate reference types (in production code) from the following addresses:

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

To:

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

A few other words

>You don't need to write an after method here, because JUnit creates a new instance when each method runs, so your method just adds the code to be completed Note that TestNG is not Instead of creating your mocks in the before method, you may want to use the mockito annotation Don't forget the runner

For example:

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

>The stubbing code is a bit ugly for several reasons

>You should write a consistent stub

Why not write this in a clean way; For example, the indexmanager can be referenced in two cases:

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

Or don't quote it

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

There is also an imitation simulation, which is usually a sign of design smell You broke Demeter's law, which means you will encounter difficult testing, poor maintainability and difficult evolution When I say you can hear me whisper (no three paragraphs): it will cost you money Don't write legacy code! If you are practicing TDD or BDD, you will identify these problems in your code at design time, which can well prevent these problems

>However, if you are working with legacy code, you can use this deep stub syntax:

You can write this using static methods

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

Or using comments, you can write this:

@Mock(answer = RETURNS_DEEP_STUBS) GraphDatabaseService graphdb;

And piles:

when(graphDb.index().getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(graphDb.index().getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>