1

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.

kriegaex
  • 63,017
  • 15
  • 111
  • 202

4 Answers4

0

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.

kriegaex
  • 63,017
  • 15
  • 111
  • 202
0

If you need to enforce that some functionality in Parent is called, you should enforce it via design not tests.

abstract class Parent {
  public final void method() {
    // Some calculations
    additionalLogic();
  }

  protected abstract void additionalLogic();
}

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

You could of course not make it abstract and just add a no-op implementation for additionalLogic() instead.

Leonard Brünings
  • 12,408
  • 1
  • 46
  • 66
  • 1
    This answer happens to be the [Template Method](https://sourcemaking.com/design_patterns/template_method) design pattern. – jaco0646 Feb 15 '20 at 20:01
0

tim_yates and kriegaex are the big beasts in the jungle when it comes to good and bad Spock, or TDD-style testing generally ... they have more than once (rightly) picked apart my questions in the way they do here, basically on the basis of testing the code rather than the implementation.

Sometimes it's difficult though. Maybe there can be cases in which you would want to test for the calling of super.doSomething(). I am just putting together, using TDD, having already done a "spike", in which I rushed ahead without testing, an editor for a TreeTableView. The "spike" can be seen here. In a constructive comment to my answer, kleopatra advised me to check (i.e. put an if in the app code) to make sure that super.startEdit() had indeed started the editing of the cell before going further, so in this case it is not sufficient to test the "side-effect" of super.startEdit() as being that isEditing() now returns true. You genuinely need to know that your class's startEdit() actually does nothing more nor less than call super.startEdit().

However, I don't believe it can be done, and tim_yates or kriegaex would almost certainly have said how you could do that if it were possible.

My suggested TDD solution would therefore be something like this:

def 'super start edit should be called if cell is not empty'(){
    given:
    // NB has to be GroovySpy because isEmpty() is final
    DueDateEditor editor = GroovySpy( DueDateEditor ){
        isEmpty() >> false
    }

    when:
    editor.startEdit()

    then:
    1 * editor.callSuperStartEdit()
}


class DueDateEditor extends TreeTableCell {

    @Override
    void startEdit(){
        if( ! isEmpty() ) {
            // this is the line you have to add to make the test pass
            callSuperStartEdit()
        }
    }

    def callSuperStartEdit(){
        super.startEdit()
    }
}

I think you have to "spawn" an artificial single-purpose method since there is, precisely, no side effect at all!

PS I will in fact parameterise this test so that it returns true to isEmpty() in the second call, and require the method NOT to be called in that case.

mike rodent
  • 14,126
  • 11
  • 103
  • 157
-3

I´ve never used the Spock framework, but i think you can check the type of the instance in the Parent.method with instance of operator or reflection.