Spock Spy/Mock not registering the invocations

Sunny :

I have a method in my test class that just calls two other methods. I am trying to write a test that checks that those two methods are actually invoced, but no invocations are registered. Java code I'm testing:

    public void populateEdgeInfo(Map<Actor, SchedulableNode> knownNodes) {
        populateDestinationInfo(knownNodes);
        populateSourceInfo(knownNodes);
    }

My test code:

def "Populating edge info means both source and destination information will be populated" () {
    given:
    actor.getDstChannels() >> []
    actor.getSrcChannels() >> []
    SchedulableNode schedulable = Spy(SchedulableNode, constructorArgs: [actor])

    when:
    schedulable.populateEdgeInfo([:])

    then:
    1 * schedulable.populateDestinationInfo(_)
    1 * schedulable.populateSourceInfo(_)
}

The only thing registered is the call to populateEdgeInfo. Is there something obvious that I am doing wrong? Also tried using Mock instead of Spy to no avail.

kriegaex :

I tried to create an MCVE from your sparse information and found no problems in your test:

package de.scrum_master.stackoverflow.q60926015;

import java.util.List;

public class Actor {
  public List getDstChannels() {
    return null;
  }

  public List getSrcChannels() {
    return null;
  }
}
package de.scrum_master.stackoverflow.q60926015;

import java.util.Map;

public class SchedulableNode {
  private Actor actor;

  public SchedulableNode(Actor actor) {
    this.actor = actor;
  }

  public void populateEdgeInfo(Map<Actor, SchedulableNode> knownNodes) {
    populateDestinationInfo(knownNodes);
    populateSourceInfo(knownNodes);
  }

  public void populateDestinationInfo(Map<Actor, SchedulableNode> knownNodes) {}

  public void populateSourceInfo(Map<Actor, SchedulableNode> knownNodes) {}
}
package de.scrum_master.stackoverflow.q60926015

import spock.lang.Specification

class SchedulableNodeTest extends Specification {
  def actor = Mock(Actor)

  def "Populating edge info means both source and destination information will be populated"() {
    given:
    actor.getDstChannels() >> []
    actor.getSrcChannels() >> []
    SchedulableNode schedulable = Spy(SchedulableNode, constructorArgs: [actor])

    when:
    schedulable.populateEdgeInfo([:])

    then:
    1 * schedulable.populateDestinationInfo(_)
    1 * schedulable.populateSourceInfo(_)
  }
}

That means that your code must be different from mine. My guess is that both populate* methods are private in your class, which makes it impossible to mock them because mocks use dynamic proxies and the latter are sub-classes technically. Sub-classes do not see private super-class methods, though, thus a dynamic proxy cannot intercept (calls to) them.

Possible solutions:

  • Stop over-specifying your tests and testing internal interactions. It makes the test brittle and you have to refactor it often if you also refactor the class under test.

  • Make the populate* methods protected or package-scoped if public is not right. Then you can stub them and check interactions on them.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=373904&siteId=1