ViV
ViV

Reputation: 2118

Mockito asks to add @PrepareForTest for the class even after adding @PrepareForTest

I have the following simple code. I have a class (TestClass) and I want to test "someMethod". There is an external static method which is called by my "someMethod". I want to Powermock that static method to return me some dummy object. I have the @PrepareForTest(ExternalClass.class) in the begining, but when I execute it gives the error:

The class ExternalClass not prepared for test. To prepare this class, add class to the '@PrepareForTest' annotation. In case if you don't use this annotation, add the annotation on class or method level.

Please help me to point out what is wrong with the way I have used @PrepareForTest

@RunWith(PowerMockRunner.class)
@PrepareForTest(ExternalClass.class)
public class xyzTest {  
    @Mock
    private RestTemplate restTemplate;

    @Mock
    private TestClass testClass;

    @BeforeClass
    private void setUpBeforeClass() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testSuccessCase() {
        Boolean mockResponse = true;
        ResponseEntity<Boolean> response = new ResponseEntity<Boolean>(mockResponse, HttpStatus.OK);
        SomeClass someClass = new SomeClass("test", "1.0.0", "someUrl", "someMetaData");

        PowerMockito.mockStatic(ExternalClass.class);

        Mockito.when(restTemplate.postForEntity(any(String.class), any(String.class), eq(Boolean.class))).thenReturn(response);
        Mockito.when(ExternalClass.getSomeClass(any(String.class))).thenReturn(someClass);

        Boolean result = testClass.someMethod("test");

        Assert.isTrue(result);
        Mockito.verify(restTemplate, times(1)).postForObject(any(String.class), any(String.class), any());
    }
}

Upvotes: 43

Views: 108666

Answers (12)

Garry Kevin
Garry Kevin

Reputation: 343

My gradle was using Junit 5.

test {
    useJUnitPlatform()
}

I was able to debug this. By having breakpoints in PowerMockRunner methods. It was not invoked. Moreover JUnit 5 is not supported with PowerMockito.

Looks like JUnit5 runs without @ExtendWith.

Upvotes: 0

Rohit Bhalke
Rohit Bhalke

Reputation: 147

Make sure you are using powermock2. I had this problem when I was using powermock. Use

import org.powermock2.api.mockito.PowerMockito;

Upvotes: -1

Sudipdev
Sudipdev

Reputation: 51

check if import org.junit.Test; package has imported and not that api jupiter one.

Upvotes: 5

jyo
jyo

Reputation: 11

For testNG there are 2 options as follows :

  1. Using ObjectFactory as below:
    @ObjectFactory
    public IObjectFactory getObjectFactory() {
        return new PowerMockObjectFactory();
    }
  1. Test class extending extends org.powermock.modules.testng.PowerMockTestCase

Upvotes: 0

wild_nothing
wild_nothing

Reputation: 3031

Make sure you add @RunWith(PowerMockRunner.class) to the top of your class as well.

::edit:: two years later...

Don't ever use PowerMockito, you shouldn't need to.

If you do need to, you have most likely broken the SOLID principles and your design is wrong.

Fix your design instead.

Upvotes: 38

Eugene
Eugene

Reputation: 120978

While the top-rated answer here is correct without a doubt, this does not answer the question of why is that needed; or, for example, why the same thing would not work with adding @RunWith(MockitoJUnitRunner.class).

The thing is PowerMockRunner uses instrumentation API under the hood, via javassist library, this allows to alter the classes, like remove final or mock static (non-compile time constants).

In the process of modifying (instrumenting) a certain class, they add an interface to that, called PowerMockModified. It is a marker interface that denotes that a certain byte-code instrumentation took place. Later in the code, they simply check if the class that you use in @PrepareForTest was actually instrumented in some way or not, via such a method:

    private boolean isModifiedByPowerMock() {
        return PowerMockModified.class.isAssignableFrom(this.type);
    }

In turns out that PowerMockRunner does some instrumentation, while MockitoJUnitRunner does not; thus the error you get.

Upvotes: 12

Will_Panda
Will_Panda

Reputation: 534

I had the same error. I was using TestNG to run the tests. I had to use the following method to fix the above issue.

@ObjectFactory
    public IObjectFactory getObjectFactory() {
        return new PowerMockObjectFactory();
    }

Upvotes: 1

Akshay Thorve
Akshay Thorve

Reputation: 718

If above answers don't work try extends PowerMockTestCase. This trick worked for me.

Example: public class xyzTest extends PowerMockTestCase

Upvotes: 3

Aaron Tobias
Aaron Tobias

Reputation: 133

For those trying to get this working with Junit 5, If your using the powermock-module-junit4 beta release which claims to be compatible with 4+, the library will still not recognize:

import org.junit.jupiter.api.Test;

and it will throw a:

org.powermock.api.mockito.ClassNotPreparedException

when @PrepareForTest is applied on the class you want to static mock. If you want to use PowerMock, you will have to go back to Junit 4 or create a MockWrapper for your static method at this time.

PowerMock 2.0: Github Roadmap

Upvotes: 13

Felicia Agatha
Felicia Agatha

Reputation: 369

I had the same error, resolved this by adding

@Rule
public PowerMockRule rule = new PowerMockRule();

inside the test class.

Upvotes: 8

user2121316
user2121316

Reputation: 191

As with the last answer, my problem was also mixing the Test annotation from TestNG instead of Junit Test.

import org.junit.Test; // works

import org.testng.annotations.Test // did not work

Very abstruse error and I spent more than 5 hrs debugging :(

Upvotes: 19

Dan
Dan

Reputation: 1083

I had the same error but resolved it. My problem was that I included powermock-module-junit4 but included my test annotation from TestNG instead of Junit.

Upvotes: 2

Related Questions