@Runwith(Mockitojunitrunner.Class) VS Mockitoannotations.Initmocks(This)

@RunWith(MockitoJUnitRunner.class) vs MockitoAnnotations.initMocks(this)

MockitoJUnitRunner gives you automatic validation of framework usage, as well as an automatic initMocks().

The automatic validation of framework usage is actually worth having. It gives you better reporting if you make one of these mistakes.

  • You call the static when method, but don't complete the stubbing with a matching thenReturn, thenThrow or then. (Error 1 in the code below)

  • You call verify on a mock, but forget to provide the method call
    that you are trying to verify. (Error 2 in the code below)

  • You call the when method after doReturn, doThrow or
    doAnswer and pass a mock, but forget to provide the method that
    you are trying to stub. (Error 3 in the code below)

If you don't have validation of framework usage, these mistakes are not reported until the following call to a Mockito method. This might be

  • in the same test method (like error 1 below),
  • in the next test method (like error 2 below),
  • in the next test class.

If they occur in the last test that you run (like error 3 below), they won't be reported at all.

Here's how each of those types of errors might look. Assume here that JUnit runs these tests in the order they're listed here.

@Test
public void test1() {

// ERROR 1
// This compiles and runs, but it's an invalid use of the framework because
// Mockito is still waiting to find out what it should do when myMethod is called.
// But Mockito can't report it yet, because the call to thenReturn might
// be yet to happen.
when(myMock.method1());

doSomeTestingStuff();

// ERROR 1 is reported on the following line, even though it's not the line with
// the error.
verify(myMock).method2();

}

@Test
public void test2() {

doSomeTestingStuff();

// ERROR 2
// This compiles and runs, but it's an invalid use of the framework because
// Mockito doesn't know what method call to verify. But Mockito can't report
// it yet, because the call to the method that's being verified might
// be yet to happen.
verify(myMock);
}

@Test
public void test3() {

// ERROR 2 is reported on the following line, even though it's not even in
// the same test as the error.
doReturn("Hello").when(myMock).method1();

// ERROR 3
// This compiles and runs, but it's an invalid use of the framework because
// Mockito doesn't know what method call is being stubbed. But Mockito can't
// report it yet, because the call to the method that's being stubbed might
// be yet to happen.

doReturn("World").when(myMock);

doSomeTestingStuff();

// ERROR 3 is never reported, because there are no more Mockito calls.
}

Now when I first wrote this answer more than five years ago, I wrote

So I would recommend the use of the MockitoJUnitRunner wherever possible. However, as Tomasz Nurkiewicz has correctly pointed out, you can't use it if you need another JUnit runner, such as the Spring one.

My recommendation has now changed. The Mockito team have added a new feature since I first wrote this answer. It's a JUnit rule, which performs exactly the same function as the MockitoJUnitRunner. But it's better, because it doesn't preclude the use of other runners.

Include

@Rule 
public MockitoRule rule = MockitoJUnit.rule();

in your test class. This initialises the mocks, and automates the framework validation; just like MockitoJUnitRunner does. But now, you can use SpringJUnit4ClassRunner or any other JUnitRunner as well. From Mockito 2.1.0 onwards, there are additional options that control exactly what kind of problems get reported.

Why we use Mockitojunitrunner class in our junit test?

Using MockitoJunitRunner rather than JunitRunner is really optional.

The automatic validation of framework usage is actually worth having.
It gives you better reporting if you make one of these mistakes.

The main advantage provided by MockitoJunitRunner is relieving you to explicitly invoke MockitoAnnotations.initMocks(Object) when you use the @Mock way to create your mocks.

But you could also get a few more misuse reports of the Mockito framework by using this runner that may be missing without using it.

The javadoc of the Mockito 1.10.19 version states :

Compatible with JUnit 4.4 and higher, this runner adds following
behavior:

  • Initializes mocks annotated with Mock, so that explicit usage of
    MockitoAnnotations.initMocks(Object) is not necessary. Mocks are
    initialized before each test method.

  • validates framework usage after each test method. See javadoc for
    Mockito.validateMockitoUsage().

And the most important part :

Runner is completely optional - there are other ways you can get @Mock
working, for example by writing a base class. Explicitly validating
framework usage is also optional because it is triggered automatically
by Mockito every time you use the framework.
See javadoc for
Mockito.validateMockitoUsage().

Example of incorrect uses that may be caught out of the box without using the MockitoJunitRunner :

 //Oops, thenReturn() part is missing:
when(mock.get());

//Oops, verified method call is inside verify() where it should be on the outside:
verify(mock.execute());

//Oops, missing method to verify:
verify(mock);

But these could not be caught in all cases.

The Mockito.validateMockitoUsage() method that is invoked by the runner and the framework itself gives more explanations about it but in fact it is not complete.

validateMockitoUsage() explicitly validates the framework state to
detect invalid use of Mockito. However, this feature is optional
because Mockito validates the usage all the time... but there is a
gotcha so read on
.

Ok. Go on.

Mockito throws exceptions if you misuse it so that you know if your
tests are written correctly. The gotcha is that Mockito does the
validation next time you use the framework (e.g. next time you verify,
stub, call mock etc.). But even though the exception might be thrown
in the next test, the exception message contains a navigable stack
trace element
with location of the defect. Hence you can click and
find the place where Mockito was misused.

So, the framework does the validation the next time you use the framework (verify, stub, call mock,etc..).

In fact it is true but not always.

For example this misuse will be caught by the framework :

@Test
public void testBadUseWhen() throws Exception {
Address mock = Mockito.mock(Address.class);
Mockito.verify(mock.getAddressLine());
}

org.mockito.exceptions.misusing.NullInsteadOfMockException: Argument
passed to verify() should be a mock but is null!

But this misuse will not be caught :

@Test
public void testBadUseWhen() throws Exception {
Address mock = Mockito.mock(Address.class);
Mockito.when(mock.getAddressLine());
}

While if I add a new use of Mockito after this uncaught misuse, this time we will get a validation exception :

@Test
public void testBadUseWhen() throws Exception {
Address mock = Mockito.mock(Address.class);
Mockito.when(mock.getAddressLine());
Mockito.when(mock.getAddressLine());
}

org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here

It will be raised for the second Mockito.when(mock.getAddressLine()); statement invoked but the exception will reference the first Mockito.when(mock.getAddressLine()); statement invoked.

It means that for some bad uses of the framework, you could lose the report information if the last mockito method you are used is incorrectly used.

The javadoc states then :

Sometimes though, you might want to validate the framework usage
explicitly. For example, one of the users wanted to put
validateMockitoUsage() in his @After method so that he knows
immediately when he misused Mockito. Without it, he would have known
about it not sooner than next time he used the framework. One more
benefit of having validateMockitoUsage() in @After is that jUnit
runner and rule will always fail in the test method with defect
whereas ordinary 'next-time' validation might fail the next test
method. But even though JUnit might report next test as red, don't
worry about it and just click at navigable stack trace element in the
exception message to instantly locate the place where you misused
mockito.

So, to not loosing a potentially misuse for the last one Mockito method invoked during a test class, you can explicitly invoke Mockito.validateMockitoUsage() after each tested method.

So this will do the trick :

@After
public void after() {
Mockito.validateMockitoUsage();
}

The alternative is using the MockitoJUnitRunner that under the hood invokes Mockito.validateMockitoUsage() after each executed test :

@Override
public void testFinished(Description description) throws Exception {
super.testFinished(description);
try {
Mockito.validateMockitoUsage();
} catch(Throwable t) {
notifier.fireTestFailure(new Failure(description, t));
}
}

@RunWith(MockitoJUnitRunner.class) doesn't initialize mocks

The runner handles the @Mock annotation after the class is instantiated, so move the filter = new Filter(transactionManager,searchManager, DOMAIN); in a @Before annotated method:

@RunWith(MockitoJUnitRunner.class)
public class MyTestClass
{
private static final String DOMAIN = "mock";

@Mock
private TransactionManager transactionManager;

@Mock
private SearchManager searchManager;

private Filter filter;

@Before
public void setup() throws Exception {
filter = new Filter(transactionManager, searchManager, DOMAIN);
}

@Test
public void myTest() throws Exception {
filter.callMethod(); // No more NPE
}
}

From the runner doc:

Initializes mocks annotated with @Mock, so that explicit usage of MockitoAnnotations.initMocks(Object) is not necessary. Mocks are initialized before each test method.

Initialising mock objects - Mockito

For the mocks initialization, using the runner or the MockitoAnnotations.initMocks are strictly equivalent solutions. From the javadoc of the MockitoJUnitRunner :

JUnit 4.5 runner initializes mocks annotated with Mock, so that explicit usage of MockitoAnnotations.initMocks(Object) is not necessary. Mocks are initialized before each test method.


The first solution (with the MockitoAnnotations.initMocks) could be used when you have already configured a specific runner (SpringJUnit4ClassRunner for example) on your test case.

The second solution (with the MockitoJUnitRunner) is the more classic and my favorite. The code is simpler. Using a runner provides the great advantage of automatic validation of framework usage (described by @David Wallace in this answer).

Both solutions allows to share the mocks (and spies) between the test methods. Coupled with the @InjectMocks, they allow to write unit tests very quickly. The boilerplate mocking code is reduced, the tests are easier to read. For example:

@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {

@Mock private ArticleCalculator calculator;
@Mock(name = "database") private ArticleDatabase dbMock;
@Spy private UserProvider userProvider = new ConsumerUserProvider();

@InjectMocks private ArticleManager manager;

@Test public void shouldDoSomething() {
manager.initiateArticle();
verify(database).addListener(any(ArticleListener.class));
}

@Test public void shouldDoSomethingElse() {
manager.finishArticle();
verify(database).removeListener(any(ArticleListener.class));
}
}

Pros: The code is minimal

Cons: Black magic. IMO it is mainly due to the @InjectMocks annotation. With this annotation "you loose the pain of code" (see the great comments of @Brice)


The third solution is to create your mock on each test method.
It allow as explained by @mlk in its answer to have "self contained test".

public class ArticleManagerTest {

@Test public void shouldDoSomething() {
// given
ArticleCalculator calculator = mock(ArticleCalculator.class);
ArticleDatabase database = mock(ArticleDatabase.class);
UserProvider userProvider = spy(new ConsumerUserProvider());
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);

// when
manager.initiateArticle();

// then
verify(database).addListener(any(ArticleListener.class));
}

@Test public void shouldDoSomethingElse() {
// given
ArticleCalculator calculator = mock(ArticleCalculator.class);
ArticleDatabase database = mock(ArticleDatabase.class);
UserProvider userProvider = spy(new ConsumerUserProvider());
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);

// when
manager.finishArticle();

// then
verify(database).removeListener(any(ArticleListener.class));
}
}

Pros: You clearly demonstrate how your api works (BDD...)

Cons: there is more boilerplate code. (The mocks creation)


My recommandation is a compromise. Use the @Mock annotation with the @RunWith(MockitoJUnitRunner.class), but do not use the @InjectMocks :

@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {

@Mock private ArticleCalculator calculator;
@Mock private ArticleDatabase database;
@Spy private UserProvider userProvider = new ConsumerUserProvider();

@Test public void shouldDoSomething() {
// given
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);

// when
manager.initiateArticle();

// then
verify(database).addListener(any(ArticleListener.class));
}

@Test public void shouldDoSomethingElse() {
// given
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);

// when
manager.finishArticle();

// then
verify(database).removeListener(any(ArticleListener.class));
}
}

Pros: You clearly demonstrate how your api works (How my ArticleManager is instantiated). No boilerplate code.

Cons: The test is not self contained, less pain of code

How to use Mockito with JUnit5

There are different ways to use Mockito - I'll go through them one by one.

Manually

Creating mocks manually with Mockito::mock works regardless of the JUnit version (or test framework for that matter).

Annotation Based

Using the @Mock-annotation and the corresponding call to MockitoAnnotations::initMocks
to create mocks works regardless of the JUnit version (or test framework for that matter but Java 9 could interfere here, depending on whether the test code ends up in a module or not).

Mockito Extension

JUnit 5 has a powerful extension model and Mockito recently published one under the group / artifact ID org.mockito : mockito-junit-jupiter.

You can apply the extension by adding @ExtendWith(MockitoExtension.class) to the test class and annotating mocked fields with @Mock. From MockitoExtension's JavaDoc:

@ExtendWith(MockitoExtension.class)
public class ExampleTest {

@Mock
private List list;

@Test
public void shouldDoSomething() {
list.add(100);
}

}

The MockitoExtension documentation describes other ways to instantiate mocks, for example with constructor injection (if you rpefer final fields in test classes).

No Rules, No Runners

JUnit 4 rules and runners don't work in JUnit 5, so the MockitoRule and the Mockito runner can not be used.

Running Tests with MockitoJUnitRunner fails verify asserts

You should understand what does this runner actually do:

Basically it allows injecting mocks (prepared by mockito with Mockito.mock(...) ) into the test fields annotated with @Mock. In the question, since you've commented out the runner, all these fields will be null.

When you annotated something with @InjectMocks - it will inject the mocks into the fields of the object of type of the annotated reference.

One more point to clarify here: MockitoAnnotations.initMocks(this) will do the same as the "runner" so no need to include both (you should use initMocks if you can't use the runner for some reason, like if there is already another runner that must be used)

Now, you ask:

Is there a way to mock a Repository without the @RunWith(MockitoJUnitRunner) annotation on the class?

The answer is - yes, you can, in fact you don't have to use the runner, sometimes its more convenient.

So, assuming you really use this runner, the real question is what exactly do you mean by "my repository doesn't work". Does this mean that there exists a reference in the service that points of this repository and its null?

Does it mean that there is a mock of repository but when you execute the call "under the test" the mock is different?

You don't show it in the code, but I assume you have some like this:

public class ServiceImpl {
private final EditStepRepository editStepRepository;

public ServiceImpl(EditStepRepository editStepRepository) {
this.editStepRepository = editStepRepository;
}
...
}

But if so, once you create a mock (and indeed there should be a mock injected into the ServiceImpl class (check this out with debugger or something), There should be expectatations specified on the repository, usually there should be code like this in the test:

Mockito.when(editStepRepository.doSomething(...)).thenReturn(...)

You haven't placed any of these lines, that why it doesn't work.

But all-in-all since the question contains many uncertain technicalities like this, I can't tell more than that other that speculating...

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

The SpringRunner provides support for loading a Spring ApplicationContext and having beans @Autowired into your test instance. It actually does a whole lot more than that (covered in the Spring Reference Manual), but that's the basic idea.

Whereas, the MockitoJUnitRunner provides support for creating mocks and spies with Mockito.

However, with JUnit 4, you can only use one Runner at a time.

Thus, if you want to use support from Spring and Mockito simultaneously, you can only pick one of those runners.

But you're in luck since both Spring and Mockito provide rules in addition to runners.

For example, you can use the Spring runner with the Mockito rule as follows.

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {

@Rule
public MockitoRule rule = MockitoJUnit.rule();

@Mock
MyService myService;

// ...
}

Though, typically, if you're using Spring Boot and need to mock a bean from the Spring ApplicationContext you would then use Spring Boot's @MockBean support instead of simply @Mock.

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

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?



Related Topics



Leave a reply



Submit