Is it possible to do strict mocks with Mockito?

折月煮酒 提交于 2020-02-26 11:36:26

问题


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?


回答1:


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();
    }
}



回答2:


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)
    ...



回答3:


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.



回答4:


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)




回答5:


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.




回答6:


Bellow Methods can verify no unexpected method called:

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


来源:https://stackoverflow.com/questions/8003278/is-it-possible-to-do-strict-mocks-with-mockito

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!