devoured elysium
devoured elysium

Reputation: 105067

Is it possible to do strict mocks with Mockito?

I'd like to use strict mocks, at least when developing for the first time some tests against old code, so any methods invoked on my mock will throw an exception if I didn't specifically define expectations.

From what I've come to see, Mockito if I didn't define any expectations will just return null, which will later on cause a NullPointerException in some other place.

Is it possible to do that? If yes, how?

Upvotes: 23

Views: 15707

Answers (6)

wangf
wangf

Reputation: 925

Bellow Methods can verify no unexpected method called:

org.mockito.Mockito#only
org.mockito.Mockito#verifyNoMoreInteractions

Upvotes: -1

user1325158
user1325158

Reputation: 224

In addition to the MockitoRule approach, if you don't need to use a specific test runner (and you are using Mockito 2.5.1 or higher), you could also consider using the MockitoJUnitRunner.StrictStubs runner, i.e.

@RunWith(MockitoJUnitRunner.StrictStubs.class)

(I would have commented on the post about MockitoRule, but don't have that ability yet)

Upvotes: 1

Dave Newton
Dave Newton

Reputation: 160191

What do you want it to do?

You can set it to RETURN_SMART_NULLS, which avoids the NPE and includes some useful info.

You could replace this with a custom implementation, for example, that throws an exception from its answer method:

@Test
public void test() {
    Object mock = Mockito.mock(Object.class, new NullPointerExceptionAnswer());
    String s = mock.toString(); // Breaks here, as intended.
    assertEquals("", s);
}

class NullPointerExceptionAnswer<T> implements Answer<T> {
    @Override
    public T answer(InvocationOnMock invocation) throws Throwable {
        throw new NullPointerException();
    }
}

Upvotes: 15

Matt Klein
Matt Klein

Reputation: 8424

Add this @Rule to your test class as a public field:

@RunWith(JUnitParamsRunner.class)
public class MyClassTests {

    @Rule
    public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);

    @Test
    ....
}

This value was added to Mockito in version 2.3.0

From the documentation:

Ensures clean tests, reduces test code duplication, improves debuggability. Offers best combination of flexibility and productivity. Highly recommended. Planned as default for Mockito v3. Adds following behavior:

  • Improved productivity: the test fails early when code under test invokes stubbed method with different arguments (see PotentialStubbingProblem).
  • Cleaner tests without unnecessary stubbings: the test fails when unused stubs are present (see UnnecessaryStubbingException).
  • Cleaner, more DRY tests ("Don't Repeat Yourself"): If you use Mockito.verifyNoMoreInteractions(Object...) you no longer need to explicitly verify stubbed invocations. They are automatically verified for you.

Upvotes: 8

palacsint
palacsint

Reputation: 28865

You could use verifyNoMoreInteractions. It's useful if the tested class catches exceptions.

@Test
public void testVerifyNoMoreInteractions() throws Exception {
    final MyInterface mock = Mockito.mock(MyInterface.class);

    new MyObject().doSomething(mock);

    verifyNoMoreInteractions(mock); // throws exception
}

private static class MyObject {
    public void doSomething(final MyInterface myInterface) {
        try {
            myInterface.doSomethingElse();
        } catch (Exception e) {
            // ignored
        }
    }
}

private static interface MyInterface {
    void doSomethingElse();
}

Result:

org.mockito.exceptions.verification.NoInteractionsWanted: 
No interactions wanted here:
-> at hu.palacsint.CatchTest.testVerifyNoMoreInteractions(CatchTest.java:18)
But found this interaction:
-> at hu.palacsint.CatchTest$MyObject.doSomething(CatchTest.java:24)
Actually, above is the only interaction with this mock.
    at hu.palacsint.stackoverflow.y2013.q8003278.CatchTest.testVerifyNoMoreInteractions(CatchTest.java:18)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    ...

Upvotes: 12

Dan Bergh Johnsson
Dan Bergh Johnsson

Reputation: 1004

According to the source code of org.mockito.Mockito.RETURNS_DEFAULTS it selects its "what to do if no expectation" from a global setting. Furthermore "If there is no global configuration then it uses {@link ReturnsEmptyValues} (returns zeros, empty collections, nulls, etc.)" I have not yet been able to make that configuration.

Upvotes: 0

Related Questions