# Understanding @PrepareForTest

PowerMock is a powerful library that works on byte code level of our program.

### PrepareForTest annotation <a href="#heading-preparefortest-annotation" id="heading-preparefortest-annotation"></a>

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.

Here are some f the use cases for PrepareForTest:

#### Mock static methods:

```java
@RunWith(PowerMockRunner.class)
@PrepareForTest({
 ClassWithStaticMethods.class,
})
public class ClassToTest {
 @Before
 public void setUp() throws Exception {
     PowerMockito.mockStatic(ClassWithStaticMethods.class);
     PowerMockito.when(ClassWithStaticMethods.staticMethod()).thenReturn(someValue);
 }
}
```

#### Mock final classes/methods:

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()`.

```java
@RunWith(PowerMockRunner.class)
@PrepareForTest({
 FinalClass.class,
 ClassWithFinalMethods.class,
})
public class ClassToTest {
 @Test
 public void testFinalMethods() throws Exception {
     final FinalClass mckFinalClass = PowerMockito.mock(FinalClass.class);
     PowerMockito.when(mckFinalClass.someMethod()).thenReturn(someValue);

     final ClassWithFinalMethods mckClassWithFinalMethods = PowerMockito.mock(ClassWithFinalMethods.class);
     PowerMockito.when(mckClassWithFinalMethods.someFinalMethod()).thenReturn(someValue);
 }
}
```

#### Inject with PowerMockito.whenNew()

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.

```java
// Example Source Class
public class ExampleClass {
 public int getHeight() {
     // Lets say we have a generic method which provides different result base on the provided id
     final CustomClass customClassInstance = new CustomClass();
     return customClass.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()`:

```java
@RunWith(PowerMockRunner.class)
@PrepareForTest({
 ExampleClass.class
})
public class ExampleClassTest {

 private ExampleClass classUnderTest;

 @Before
 public void setUp() throws Exception {
     // Create constructor of ExampleClass
     classUnderTest = new ExampleClass();
 }

 @Test
 public void getHeight_shoudReturnHeightOfView() throws NoSuchMethodException {
     final int expectedHeight = 100;
     // Given
     final CustomClass 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);

     final int 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.

```java
// Suppress Constructor
PowerMockito.suppress(CustomLibClass.class.getConstructors());
// Suppress Method, it will return null if method has a return.
PowerMockito.suppress(CustomLibClass.class.getDeclaredMethod("someMethod"));
```

`stub()` methods to return different value.

```java
PowerMockito.stub(
    CustomLibClass.class.getDeclaredMethod("someMethodThatOnlyWorksOnRumtime")
).toReturn(2);
```

`replace()` methods to return different value depending on parameter supplied.

```java
PowerMockito.replace(View.class.getDeclaredMethod("someMethodThatWillReturnDifferentValue", int.class)).with(new InvocationHandler() {
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      final int viewId = (int) args[0];

      if (viewId == ViewFactory.text_view) {
          // return mock of TextView
          return Mockito.mock(TextView.class);
      } else if (viewId == ViewFactory.image_view) {
          // return mock of ImageView
          return Mockito.mock(ImageView.class);
      }
      // else you can call real method as well
      return method.invoke(proxy, args);
  }
});
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://notes.tejpratapsingh.com/_/java-testing/powermockito/preparefortest/understanding-preparefortest.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
