Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verifying that a protected super method is invoked

I have the following structure:

class Bar{
  ....
  protected void restore(){
    ....
  }

  ....
}

This class is extended by Foo as below:

class Foo extends Bar{
    ....

    @Override
    public void restore(){  //valid override
        super.restore();

        ....
    }
}

In my jUnit test I would like to test that when foo.restore() is called, the super.restore() is called subsequently. Hence, below is my jUnit test method:

class FooTest{
  @Tested
  Foo _foo;

  @Test
  void testRestore(final Bar bar){

    new Expectations(){{
      bar.restore(); times = 1; // Error! bar.restore() not visible
    }};

    Deencapsulation.invoke(_foo,"restore");
  }
}

Unfortunately, my test cannot compile. The reason is that 1) the restore() of the parent is protected and 2) FooTest and Foo exist together in a separate project (and therefore folder) vs. Bar.

Is there anyway to achieve the desired test? I have checked the jMockit tutorials (many times over the past few months) and have not seen a similar test (same goes for a search on Google).


Update

With the help of the responses, I understand that enforcing subclasses to invoke super is not the best practice, yet this is not my implementation and I still have to test it. I am still looking for a way to enforce my jUnit test to check if the call to the parent is taking place.

like image 240
arin Avatar asked Jan 11 '13 20:01

arin


3 Answers

So basically you are trying to enforce a contract of calling the super and trying to allow for subclassing? I think that this is not easily done due to the dynamic dispatch that will hide the behavior in Java. I don't think that Mocking will catch this.

A way the ensure that the super is called would be to break out the super and the extension into 2 methods like

class Foo {
  public final void restore() {
    //parent code...
    doRestore();
  }

  protected void doRestore() {
    //empty base implementation
  }
}

class Bar extends Foo {
    protected void doRestore() {
      //do my subclass specific restore stuff here
    } 
}
like image 116
toths Avatar answered Oct 14 '22 06:10

toths


The following test should work:

public class FooTest
{
    @Tested Foo _foo;

    @Test
    void restoreInFooCallsSuper(@Mocked final Bar bar)
    {
        new Expectations() {{
            invoke(bar, "restore");
        }};

        _foo.restore();
    }
}
like image 42
Rogério Avatar answered Oct 14 '22 04:10

Rogério


The super.restore() is supposed to do something useful no? some specific logic. In your test simply test that the outcome of invoking the super.restore() happened.

Another way to look into it is the following. In the subclass before doing anything you implement an assert that ensures that the super did its job correctly. This is a stronger check and is well known as part of Meyer's Design by Contract paradigm. In this context the subclass simply checks that the post-condition of the super.restore() implementation holds before executing and by using assert you know it will fail during Unit Tests but also during test integration runs of your application e.g.

class Foo extends Bar{
    ....

    @Override
    public void restore(){  //valid override
        super.restore();
        assert super_restore_worked_ok_condition : "restore post-condition failed";

        ....
    }
}
like image 26
SkyWalker Avatar answered Oct 14 '22 05:10

SkyWalker