PrepareForTest is very powerful tool that unlocks class manipulation capabilities by modifying class to byte code level.
PowerMock is a powerful library that works on byte code level of our program.
PrepareForTest annotation
PrepareForTest has one job, it will creates a reflection of your class at bytecode level. It allows you to manipulate your source code such that you can change behavior (implementation) of declared methods.
This comes handy when you are working with class or methods that are now allowed to be mocked by Java Reflection.
Mockito cannot mock final methods even if you have created mock of that class. To mock these methods, we need to prepare that class and mock it with PowerMockito.mock().
When you need to inject a mock instead of creating an actual instance of a class, you can use PowerMockito.whenNew(). This will inject your mock whenever new instance is created in your source class.
// Example Source ClasspublicclassExampleClass {publicintgetHeight() {// Lets say we have a generic method which provides different result base on the provided idfinalCustomClass customClassInstance =newCustomClass();returncustomClass.getHeight(); }}
In this example class, we are creating CustomClass without any injection mechanism, we can inject our mock by adding ExampleClass in PrepareForTest and using PowerMockito.whenNew():
@RunWith(PowerMockRunner.class)@PrepareForTest({ExampleClass.class})publicclassExampleClassTest {privateExampleClass classUnderTest; @BeforepublicvoidsetUp() throwsException {// Create constructor of ExampleClass classUnderTest =newExampleClass(); } @TestpublicvoidgetHeight_shoudReturnHeightOfView() throwsNoSuchMethodException {finalint expectedHeight =100;// GivenfinalCustomClass mckCustomClass =Mockito.mock(CustomClass.class);Mockito.when(mckCustomClass.getHeight()).theReturn(expectedHeight);// Make sure you match exact parameters while mocking (same as we do for Mockito.mock statements).// There is also withArguments(first, second, ....)// and withAnyArguments() for cases when you don't care for arguments passed.PowerMockito.whenNew(CustomClass.class).withNoArguments().thenReturn(mckCustomClass);finalint actualResult =classUnderTest.getHeight();Assert.assertEquals(expectedHeight, actualResult); }}
To suppress(), stub() or replace() any method of a Class. You can modify behavior of methods declared in any class, You can:
suppress() methods and constructors.
// Suppress ConstructorPowerMockito.suppress(CustomLibClass.class.getConstructors());// Suppress Method, it will return null if method has a return.PowerMockito.suppress(CustomLibClass.class.getDeclaredMethod("someMethod"));