Foreword
If you already read some other blog post about unusual mocking, you can skip prelude via this link.
I was asked to put together examples how to mock Java constructs well know for their testability issues:
I am calling these techniques unusual mocking. I was worried that such examples without any guidance can be widely used by teammates not deeply experienced in mocking frameworks.
Developers practicing TDD or BDD should be aware of testability problems behind these constructs and try to avoid them when designing their tests and modules. That is the reason why you probably wouldn’t be facing such unusual mocking often on project using these great programming methodologies.
But sometimes you have to extend or maintain legacy codebase that usually contains low cohesive classes. In most cases there isn’t time in current hectic agile world to make such class easy to unit test standard way. When you are trying to unit test such class you often realize that unusual mocking is needed.
That is why I decided to create and share refactoring considerations alongside with examples and workarounds for unusual mocking. Examples are using Mockito and PowerMock mocking frameworks and TestNG unit testing framework.
Mock final class
Refactoring considerations
Change class to non-final (remove final keyword) and test it standard way. This is technique I use always when I can change code of final class.
Usage of PowerMock
Before usage of this example, please carefully consider if it is worth to bring bytecode manipulation risks into your project. They are gathered in this blog post. In my opinion it should be used only in very rare and non-avoidable cases.
Test shows how to mock final class by PowerMock framework. Example covers:
- Mocking of method with return value in final class
- Mocking of final void method in final class
- Verifying of method calls in final class
Final class:
public final class Plane {
public static final int ENGINE_ID_RIGHT = 2;
public static final int ENGINE_ID_LEFT = 1;
public boolean verifyAllSystems() {
throw new UnsupportedOperationException("Fail if not mocked!");
}
public void startEngine(int engineId) {
throw new UnsupportedOperationException(
"Fail if not mocked! [engineId=" + engineId + "]");
}
}
Class under test:
public class Pilot {
private Plane plane;
public Pilot(Plane plane) {
this.plane = plane;
}
public boolean readyForFlight() {
plane.startEngine(Plane.ENGINE_ID_LEFT);
plane.startEngine(Plane.ENGINE_ID_RIGHT);
return plane.verifyAllSystems();
}
}
Test:
@PrepareForTest(Plane.class)
public class PilotTest extends PowerMockTestCase {
@Test
public void testReadyForFlight() {
Plane planeMock = PowerMockito.mock(Plane.class);
Pilot pilot = new Pilot(planeMock);
Mockito.when(planeMock.verifyAllSystems()).thenReturn(true);
// testing method
boolean actualStatus = pilot.readyForFlight();
Assert.assertEquals(actualStatus, true);
Mockito.verify(planeMock).startEngine(Plane.ENGINE_ID_LEFT);
Mockito.verify(planeMock).startEngine(Plane.ENGINE_ID_RIGHT);
}
}
Links
Source code can be downloaded from Github.
Other unusual mocking examples: