Can I mock a superclass's constructor with Mockito/Powermock?

Jeff Axelrod picture Jeff Axelrod · Mar 31, 2012 · Viewed 8.5k times · Source

Is it possible using Mockito and optionally Powermock to mock a superclass S such that any calls to the superclass to S (including calls to the S() constructor) are mocked? So using the below example, if I replace S with MockS using Mockito, will the call to super() use the constructor in MockS?

class S {
   S() {
      // Format user's hard drive, call 911, and initiate self-destruct
   }
}

class T extends S {
   T() {
      super();
   }
}

class Test {
   @Mock private S mockS;
   new T(); // T's call to super() should call the mock, not the destructive S.
}

I've seen questions about mocking individual methods in S or mocking only calls to super(), and read that this is unsupported, but it's not clear whether or not I can mock the entire superclass.

With my current tests, when I try to mock S, T's call to super() calls the real implementation, not the mock.

Answer

Jeff Axelrod picture Jeff Axelrod · Mar 31, 2012

To work around this apparent limitation, I refactored my code, replacing inheritance with delegation, and I think I've ended up with a better design anyhow since the inheritance wasn't really necessary.

The new code looks like this. Mind you the code for the question was simplified, so the real classes have much more functionality.

class S {
   S() {
      // Format user's hard drive, call 911, and initiate self-destruct
   }
}

class T {
   T(S s) {} // Now T "has an S" instead of "is an S"
}

class Test {
   @Mock private S mockS;
   new T(s); // T's call to super() should call the mock, not the destructive S.
}

For those interested, using Guice and Android, the test looks more like this:

class T {
   T(Activity activity, S s) {}
}

class Test {
  @Mock Activity activity;
  @Mock S mockS;
  injector = Guice.createInjector(new AbstractModule() {
     @Override protected void configure() {
        bind(Activity.class).toInstance(activity);
        bind(S.class).toInstance(mockS);
     }}
  );
  T t = injector.getInstance(T.class);
}