3

Is there anyway in Mockito/PowerMockito to mock some methods of super class.

Below is a scenario, it does a multilevel inheritance.

public class Network {
  public String getNetwork() {
    return "Technology";
  }
}

Here is another class Technology that extends Network

public class Technology extends Network {
  public Type getTechnology() {
    String network = getNetwork();
    if(network == null){
      return null;
    }
    return network;
  }
}

Another class Service that extends Technology

public class BaseService extends Technology {
  public void getServices() {
    Type type = getTechnology();
    if(type == null){
      throw new Exception('Type not found');
    }
  }
}

I want to write a test case for BaseService class method getServices, so that it should throw an exception when the technology class Type is null.

I have tried with a few steps but couldn't help.

Sample test case written

@Test
    public void test_get_services_should_throw__exception_when_type_is_null() throws Exception{

        //Arrange
        expectedException.expect(Exception.class);

        baseService = Mockito.mock(BaseService.class, Mockito.CALLS_REAL_METHODS);

        when(baseService.getTechnology()).thenReturn(null);


        //Act
        baseService.getServices();
    }

The code snippet above is just a sample and may contain errors. Please ignore if any.

Please help me to resolve this issue.

Thanks in advance.

Newbie
  • 1,403
  • 2
  • 13
  • 22
  • 2
    You want to research "partial mocking". Alternatively, Mockito spies can be used for that, too. – GhostCat Jun 05 '18 at 11:22
  • Partial mocks are the way https://static.javadoc.io/org.mockito/mockito-core/2.13.0/org/mockito/Mockito.html#16 – Nkosi Jun 05 '18 at 11:24
  • 1
    Please give somethought to redesigning your code. You're likely misusing inheritance where Strategy or State is needed (This is one of the great things about unit tests - they drive you to improve your design). Just looking at your inheritance: Technoligy IsA Network. Service IsA Technology. Does that sound right? –  Jun 05 '18 at 12:38

3 Answers3

0

Use the spy object. Here baseService would be a spy.

You can add behaviors on the spy object as you do with mock'ed ones.

I'll give you a little headstart-

baseService = Mockito.spy(new BaseService());

BTW you won't see this problem if you favor composition over inheritance.

Shanu Gupta
  • 3,699
  • 2
  • 19
  • 29
0

This should work.

@RunWith(MockitoJUnitRunner.class)
public class TestInheritance {

  @Spy
  BaseService baseService;

  @Rule
  public final ExpectedException expectedException = ExpectedException.none();

  @Test
  public void test_get_services_should_throw__exception_when_type_is_null() throws Exception{

    expectedException.expect(Exception.class);

    when(baseService.getTechnology()).thenReturn(null);

    baseService.getServices();
  }
}
pvpkiran
  • 25,582
  • 8
  • 87
  • 134
0

As other's have already written, you could do this with a spy, but I'd suggest a different approach to your testing instead.

In your very simple example, all the null-checks are irrelevant as you're always returning a constant, non-empty value. In that particular case there is no point in mocking at all.

But given that your base class may actually have different return values. Instead of mocking the parent's method, you should write your test in that way, that you trigger the alternative paths by alter the "state" (class state or global state like the environment) preconditions of your class. By this you create an actual situation where the parent behaves different.

This would create a test setup that is much more robust to changes (due to refactoring) and further provide a first form of integration testing, as you're testing whether your specialized class integrates with the parent class.

Aiming for strictly isolated unit tests may lead to test suites that don't cover collaboration between classes properly. Strictly isolated tests may form the foundation of your automation testing approach, but you should have tests with some degree of integration on top of that (not referring to "real" integration tests here, where you integrate with external services).

My advise here, use mocks only on well defined boundaries (interfaces) and use the real classes as much as possible, and design your tests accordingly (not train the mocks, prepare the preconditions instead).

Gerald Mücke
  • 10,724
  • 2
  • 50
  • 67