Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@RunWith(PowerMockRunner.class) vs @RunWith(MockitoJUnitRunner.class)

Tags:

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?

like image 602
Johan Avatar asked Jul 08 '16 14:07

Johan


People also ask

What is the meaning of @RunWith MockitoJUnitRunner class?

MockitoJUnitRunner; // @RunWith attaches a runner with the test class to initialize the test data @RunWith(MockitoJUnitRunner.

What is the use of @RunWith SpringRunner class?

@RunWith(SpringRunner. class) tells JUnit to run using Spring's testing support. SpringRunner is the new name for SpringJUnit4ClassRunner , it's just a bit easier on the eye. @SpringBootTest is saying “bootstrap with Spring Boot's support” (e.g. load application.

What is the use of Powermockrunner?

PowerMock is an open-source Java framework used for creating a mock object in unit testing. It extends other mocking frameworks such as EasyMock and Mockito to enhance the capabilities.

Can we use both Mockito and PowerMock together?

Mockito allows us to create mock objects. Since static method belongs to the class, there is no way in Mockito to mock static methods. However, we can use PowerMock along with Mockito framework to mock static methods.


2 Answers

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?

like image 92
GhostCat Avatar answered Sep 24 '22 14:09

GhostCat


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());    } } 
like image 40
Sven Avatar answered Sep 20 '22 14:09

Sven