20

In the usual mocking with @Mock and @InjectMocks annotations, the class under testing should be run with @RunWith(MockitoJUnitRunner.class).

@RunWith(MockitoJUnitRunner.class)
public class ReportServiceImplTestMockito {

     @Mock 
     private TaskService      mockTaskService;

     @InjectMocks 
     private ReportServiceImpl service;

         // Some tests
}

but in some example I am seeing @RunWith(PowerMockRunner.class) being used:

@RunWith(PowerMockRunner.class)
public class Tests {
  @Mock
  private ISomething mockedSomething;

  @Test
  public void test1() {
    // Is the value of mockedSomething here
  }

  @Test
  public void test2() {
    // Is a new value of mockedSomething here
  }
}

could someone point it out whats the difference and when I want to use one instead of another?

Johan
  • 2,763
  • 7
  • 23
  • 33

3 Answers3

33

On a first glance, the answer is simply: well, there are several mocking frameworks out there, and there are different ways to use them.

The first example tells JUnit to use the "unit test runner" that the Mockito mocking framework provides. The second example uses the unit test runner from the PowerMock framework.

In order for things to make sense, you would also have different import statements, as both frameworks have different implementations for the @Mock annotation for example.

( the main point of using these framework-specific test runners is that they take care of initializing all the fields with special framework-specific annotations ).

So: the difference here is simply that: the first example is written to use the Mockito framework, the second one uses PowerMock.

Now, which one of those to use?

Answer: Mockito.

Why? Somehow an ugly truth is: the PowerMock-one basically is a cry for help. It says "the class under test is badly designed, please fix it". Meaning: as a developer, you can write "easy to test" code, or "hard to test" code. Many people do the second: they write code that is hard to test. And then, PowerMock(ito) provides means to still test that code.

PowerMock(ito) gives you the ability to mock (thus control) calls to static methods, and to new(). To enable that, PowerMock(ito) manipulates the byte code of your code under test. That is perfectly fine for small code bases, but when you face millions of lines of production code, and thousands of unit tests, things are totally different.

I have seen many PowerMock tests fail for no apparent reason, to find out hours later ... that some "static" thing somewhere else was changed, and that somehow affect a different PowerMock static/new driven test case.

At some point, our team made a conscious decision: when you write new code, and you can only test that with PowerMock ... that isn't acceptable. Since then, we only created Mockito test cases, and not once since then we saw similar bizarre problems that bugged us with PowerMock.

The only acceptable reason to use PowerMock is when you want to test existing (maybe 3rd party) code that you do not want to modify. But of course, what is the point of testing such code? When you can't modify that code, why should tests fail all of a sudden?

GhostCat
  • 127,190
  • 21
  • 146
  • 218
  • 5
    What's up with this personal crusade against PowerMock!? Now, I understand it *is* a mocking library with certain problems, but it was created (not by me, BTW - I created another one) in an effort to solve actual problems that eventually come up when writing real-world tests. Just to give you one perfectly legitimate real-world situation where such a tool is useful: mocking the `FacesContext.getCurrentInstance()` static method so you can verify expected calls to the `addMessage(...)` method. Also, other claims being made here are factually wrong or highly debatable. – Rogério Jul 08 '16 at 17:16
  • I agree; developers shouldn't turn to a mocking library in order to avoid fixing testability problems. This is just as true as the situation in which they avoid good OO or API design in order to work around the limitations of a mocking library. To me, the best answer to both these situations is to avoid mocking altogether, and go for an *integration* test; it's what I do myself. – Rogério Jul 11 '16 at 15:42
  • 1
    There are legitimate reasons for wanting to test classes that cannot conform to a testable design, for instance, if you wanted to test a class that uses lwjgl you would either have to create a thin layer that just calls the lwjgl classes static methods, or you could use powermock for that class. One would require recreating the API your using and having to maintain that layer, not to mention that your adding extra calls on very tight loops that require high performance. Testing that code by having an automated (and itself tested) mock framework would be far superior to not testing at all. – Daniel Carlsson Sep 22 '17 at 21:38
  • @DanielCarlsson I agree, in our case, it's trying to mock things that are not even under my control (i.e. - we have no sources for), this a terrible answer IMHO without even partially addressing the question. SO can be a weird place sometimes – Eugene Apr 17 '19 at 16:01
  • 1
    @Eugene Actually, you are right. That was a really old answer, from a time when I had to fix such PowerMock issues every other week. I reworked my answer, and I think it A) addresses the question now and B) gives a more balanced view. But just to be clear here: 4 years without writing a single PowerMock test ... and I am 100% convinced that this helped us creating better code. – GhostCat Apr 18 '19 at 07:54
  • @GhostCat why do you think so many people do powermock? Its not like they really want to is a very good start of an answer... PowerMock is a very beautiful software tailored for "the rest of us" that depend on code that is very easy to test otherwise, if at all. – Eugene Apr 18 '19 at 10:55
  • @Eugene I guess you meant "this is NOT easy to test" ... Beyond that: code that is "hard to (unit) test without PowerMock)" ... is most likely just that: hard to test. Also other ways of testing are probably much harder, because of the inability to control dependencies. – GhostCat Apr 18 '19 at 11:05
  • 1
    @GhostCat I appreciate your answer because it lead me to rethinking my test and the class I was trying to test. I did refactor the class I was testing to eliminate a one liner method and then studying the code a little more I realized I did not need to use PowerMock's whenNew. – cptully Aug 07 '20 at 16:45
  • Thank you very much for your feedback. Always glad to hear that my answers get people to think! – GhostCat Aug 07 '20 at 18:04
3

PowerMock should never be your first choice. If you just written a class, which is only testable with PowerMock you did something wrong. A class should have dependency injection or a constructor with dependencies, so the testing is facilitated and of course: don't try to use static methods as these are not mockable in regular frameworks (read:mockito).

From the other hand: if you have a big project and you want to add unit tests to it because the previous developer did not do it, PowerMock can be the only solution without totally refactoring everything. And in that perspective I prefer PowerMock above no tests at all.

PowerMock is dirty as it changes the bytecode and code coverage with JaCoCo (SonarQube coverage runner) does not work, but the IntelliJ code coverage runner does work with PowerMock.

When in one class one method can't be tested with Mockito I split the test: one test class with Mockito and one test class with PowerMock. This will keep your code-coverage better in SonarQube.

public class ClassToTest {

    public void testableMethod() {
        /* Do something */
    }

    public String methodWithStaticCall() {
        return MyTest.staticMethod();
    }
}

Then I have one class to test the first method:

@RunWith(MockitoJUnitRunner.class)
public class testClassToTest() {
   private sut = new ClassToTest();

   @Test
   public testMethod() {
       sut.testableMethod();
   }
}

And one with PowerMock:

@RunWith(PowerMockJUnitRunner.class)
@PrepareForTest({MyTest.class, ClassToTest.class})
public class testClassToTestPM() {
   private sut = new ClassToTest();

   @Before
   public void before() {
       mockStatic(MyTest.class);
   }

   @Test
   public testMethod() {
       mockStatic(MyTest.class);
       when(MyTest.staticMethod()).thenReturn("test");
       assertEquals("test", sut.methodWithStaticCall());
   }
}
Sven
  • 1,733
  • 11
  • 25
0

PowerMock allows you to mock static and private methods as well as final classes and more.

PowerMock is a framework that extends other mock libraries such as EasyMock with more powerful capabilities. PowerMock uses a custom classloader and bytecode manipulation to enable mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more.

There may be some code smell if you need to mock those types of components, but it may be useful. At some point you may be working in an outdated project that created static helper classes that have dependencies that need to be mocked. If you have the ability to change the architecture, then fix your design! Otherwise, use the right technology for your tests.

If you dont need to mock static or private functions than you dont need to use PowerMock. PowerMock is a wrapper around other mocking frameworks.

Phil Ninan
  • 788
  • 1
  • 9
  • 19
  • there may indeed be some kind of code smell, but before we go about changing our code, we may want/need to have some sort of tests for it that ensures that our changes doesn't destroy the code... ;) – Haakon Løtveit Jun 14 '19 at 13:10