Mock Constructor
Join the DZone community and get the full member experience.
Join For FreeForeword
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 of 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 constructor
Refactoring considerations
- If your testing method creates instance/s of some type, there are two possibilities what can happen with these instances
- Created instance/s are returned from testing method. They are in this case part of the testing method API. This can be tested by verifying against created instances rather than constructor method call. If target instances doesn't have hashCode/equals contract implemented, you can still create test specific comparator to verify created data.
- Created instances are used as parameter/s passed to some dependency object. This dependency object of testing class is most probably mocked. In this case it's better idea to capture arguments of dependency method call and verify them. Mockito offers good support for this.
- Created instances are temporary objects that support testing method job. In this case you shouldn't care about creation of these instances, because you should treat testing module as black box that doing the job, but you don't know how.
- Create factory class for constructing instances and mock it standard way.
- If that fits to requirement -> Abstract factory design pattern
Workaround using Mockito
This is my preferred technique when I need to mock constructor. I believe that minor exposing of internal implementation in flavor to enhance testability of testing module is much lower risk for project than fall into bytecode manipulation mocking framework like PowerMock or JMockIt.
This technique involves:
- Encapsulating the constructor into method with default access modifier
- Partial mock (spy) is used to mock this method during testing
Mockito example covers:
- Partial mocking of factory method
- Verifying of mocked factory method call
Class under test:
public class CarFactoryMockito {
Car carFactoryMethod(String type, String color) {
return new Car(type, color);
}
public Car constructCar(String type, String color) {
carFactoryMethod(type, color);
// ... other logic needed to be tested ...
return carFactoryMethod(type, color);
}
}
Test:
public class CarFactoryMockitoTest {
private static final String TESTING_TYPE = "Tatra";
private static final String TESTING_COLOR = "Black";
@Test
public void testConstructCar() {
CarFactoryMockito carFactory = new CarFactoryMockito();
CarFactoryMockito carFactorySpy = Mockito.spy(carFactory);
Car mockedInstance = Mockito.mock(Car.class);
Mockito.doReturn(mockedInstance).when(carFactorySpy)
.carFactoryMethod(TESTING_TYPE, TESTING_COLOR);
// invoke testing method
Car actualInstance = carFactorySpy.constructCar(TESTING_TYPE,
TESTING_COLOR);
Assert.assertEquals(actualInstance, mockedInstance);
// ... verify other logic in constructCar() method ...
Mockito.verify(carFactorySpy, Mockito.times(2)).carFactoryMethod(
TESTING_TYPE, TESTING_COLOR);
}
}
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 constructor directly by PowerMock. Example covers:
- Mocking of constructor
- Verifying of constructor call
Class under test:
public class CarFactoryPowerMock {
public Car constructCar(String type, String color) {
new Car(type, color);
return new Car(type, color);
}
}
Test:
/**
* Demonstrates constructor mocking by PowerMock.
* <p>
* NOTE: Prepared in PowerMock annotation {@link PrepareForTest} should be class
* where is constructor called
*/
@PrepareForTest(CarFactoryPowerMock.class)
public class CarFactoryPowerMockTest extends PowerMockTestCase {
private static final String TESTING_TYPE = "Tatra";
private static final String TESTING_COLOR = "Black";
@Test
public void testConstructCar() throws Exception {
Car expectedCar = Mockito.mock(Car.class);
PowerMockito.whenNew(Car.class)
.withArguments(TESTING_TYPE, TESTING_COLOR)
.thenReturn(expectedCar);
// invoke testing method
CarFactoryPowerMock carFactory = new CarFactoryPowerMock();
Car actualCar = carFactory.constructCar(TESTING_TYPE, TESTING_COLOR);
Assert.assertEquals(actualCar, expectedCar);
// ... verify other logic in constructCar() method ...
PowerMockito.verifyNew(Car.class, Mockito.times(2)).withArguments(
TESTING_TYPE, TESTING_COLOR);
}
}
Links
Source code can be downloaded from Github.
Other unusual mocking examples:
Opinions expressed by DZone contributors are their own.
Comments