Search code examples
javaunit-testinggroovyspock

How to verify whether a super class method was called in Spock?


Imagine I had the following class structure:

class Parent {
  public void method() {
    // Some calculations
  }
}
class Child extends Parent {
  @Override
  public void method() {
    super.method();
    // Some additional logic
  }
}

I am spock-testing the Child.method and want to verify if the Parent.method is called from the Child.method. I did some research and i haven't found any satisfying solution to solve my problem.

How can I verify in a Spock test that in the call of Child.method the superclass method (Parent.method) was called as well?

Known solution: In Child move the super.method() to a separate, package-private method.

I want to know whether there is a better solution.


Solution

  • tim_yates commented:

    Why do you want to test this? Can't you tell as the super class calculations were performed?

    I completely agree. I would not test this because as @Override implies, the contract is an override, delegation to the super class method is optional. Why would you force your users to call the super class method? But as Tim said, you can test for the side effects which are important to you. Here is a little example with one side effect being a field assignment and another being something written to System.out (maybe silly, but just in order to show something non-obvious with a mock):

    package de.scrum_master.stackoverflow.q60167623;
    
    public class Parent {
      protected String name;
    
      public void method() {
        // Some calculations
        System.out.println("parent method");
        name = "John Doe";
      }
    }
    
    package de.scrum_master.stackoverflow.q60167623;
    
    class Child extends Parent {
      @Override
      public void method() {
        super.method();
        // Some additional logic
        System.out.println("child method");
      }
    
      public static void main(String[] args) {
        new Child().method();
      }
    }
    
    package de.scrum_master.stackoverflow.q60167623
    
    import spock.lang.Specification
    
    class ChildTest extends Specification {
      static final PrintStream originalSysOut = System.out
      PrintStream mockSysOut = Mock()
    
      def setup() {
        System.out = mockSysOut
      }
    
      def cleanup() {
        System.out = originalSysOut
      }
    
      def test() {
        given:
        def child = new Child()
    
        when:
        child.method()
    
        then:
        1 * mockSysOut.println({ it.contains("parent") })
        child.name == "John Doe"
      }
    }
    

    Update: What you want to do simply is not possible technically, and for a reason: It would break encapsulation, see here, here, indirectly also here. The method is overridden, the word says it all. Test for the (side) effect or the result of a method, not for its interaction (that it is actually called). Spock's interaction testing capabilities are over-used even though the Spock manual warns about over-specification in some places. It just makes your tests brittle. Interaction testing is okay for design patterns like publish/subscribe (Observer pattern) where it makes sense to test the interactions between objects as such.