Is it possible to do strict mocks with Mockito?

2020-06-08 03:25发布

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?

6条回答
祖国的老花朵
2楼-- · 2020-06-08 04:08

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.
查看更多
来,给爷笑一个
3楼-- · 2020-06-08 04:11

Bellow Methods can verify no unexpected method called:

org.mockito.Mockito#only
org.mockito.Mockito#verifyNoMoreInteractions
查看更多
男人必须洒脱
4楼-- · 2020-06-08 04:14

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)
    ...
查看更多
家丑人穷心不美
5楼-- · 2020-06-08 04:19

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();
    }
}
查看更多
Deceive 欺骗
6楼-- · 2020-06-08 04:19

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)

查看更多
我命由我不由天
7楼-- · 2020-06-08 04:27

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.

查看更多
登录 后发表回答