39

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());
    }
}
ViV
  • 1,998
  • 8
  • 27
  • 54
  • You're running this class on JUnit4 in a desktop JVM, right? And ExternalClass is _not_ a Java system class? – Jeff Bowman Jun 20 '16 at 21:48
  • 1
    Yes, I'm running it on desktop JVM (Oracle, 1.8). And ExternalClass is a custom Java Class (NOT Java system class: i.e. java*.*) – ViV Jun 27 '16 at 13:34
  • I see you're using `MockitoAnnotations.initMocks(...)` along with using the Powermock JUnit Runner. This is unnecessary. The Powermock runner will setup your mocks. I don't know if this will help your situation, because I'm having the same problem and I am not making an additional call to initialize mocks. – Bradley M Handy Jun 28 '16 at 17:54
  • For me it works just fine. What Mockito & Powermockito versions are you using? – Morfic Jul 04 '16 at 13:37
  • You should definitely check your imports as @Dan suggested. But you might also have an initialization problem caused by `@BeforeClass` annotation being applied to a non static method `setUpBeforeClass`. – Coderslang Master Dec 12 '16 at 14:06
  • I think you ca find the respononse of the problem in this link : https://stackoverflow.com/questions/52966897/powermock-java-11 – flyordie Nov 09 '21 at 08:57
  • I think you ca find the respononse of the problem in this link : https://stackoverflow.com/questions/52966897/powermock-java-11 – flyordie Nov 09 '21 at 08:57

12 Answers12

37

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.

wild_nothing
  • 2,845
  • 1
  • 35
  • 47
  • And delegate it to the springrunner so that you can integrate it with spring boot; @PowerMockRunnerDelegate(SpringRunner.class) – Levent Divilioglu Jul 11 '19 at 09:32
  • 16
    This answer is not helpful. Even if MOST of the time you should not mock static methods, converting a static method to instance method (1) may not be possible if you don't own that code and (2) may make the code more error-prone. The most likely outcome of not mocking status is not writing tests against code that calls static methods. And that's much worse. – Vroo Dec 27 '19 at 01:49
  • 3
    I agree much with @Vroo. I am right in front of such a case where so-called SOLID principles are happily violated by Apache! I have been breaking my head for two days now, on this thing. Too bad that this answer has become a top hit in SO... – Romeo Sierra Jun 04 '20 at 10:15
  • 1
    So we should add wrappers to all static methods we use? That doesn't make any sense because they exist to be used – JobHunter69 Jul 15 '20 at 18:29
  • @Goldname don't use static methods. – wild_nothing Jul 17 '20 at 09:41
  • 1
    @wild_nothing so one would need to go through the roundabout way of instantiating a class for the sole purpose of running a simple function in java? Why then do standard java classes have static methods to them? – JobHunter69 Jul 17 '20 at 18:04
17

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 :(

Renats Stozkovs
  • 2,549
  • 10
  • 22
  • 26
user2121316
  • 171
  • 1
  • 2
13

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

Aaron Tobias
  • 133
  • 1
  • 6
12

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.

Eugene
  • 117,005
  • 15
  • 201
  • 306
8

I had the same error, resolved this by adding

@Rule
public PowerMockRule rule = new PowerMockRule();

inside the test class.

Felicia Agatha
  • 359
  • 5
  • 11
4

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

Sudipdev
  • 41
  • 1
3

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

Example: public class xyzTest extends PowerMockTestCase

Akshay Thorve
  • 678
  • 6
  • 10
2

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.

Dan
  • 1,041
  • 1
  • 12
  • 32
1

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();
    }
Will_Panda
  • 534
  • 10
  • 26
0

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
samabcde
  • 6,988
  • 2
  • 25
  • 41
jyo
  • 11
0

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.

Garry Kevin
  • 303
  • 2
  • 9
-1

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

import org.powermock2.api.mockito.PowerMockito;
Rohit Bhalke
  • 147
  • 1
  • 5