Is it possible to do strict mocks with Mockito?

后端 未结 6 1384
傲寒
傲寒 2021-02-12 20:13

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 sp

相关标签:
6条回答
  • 2021-02-12 20:34

    Bellow Methods can verify no unexpected method called:

    org.mockito.Mockito#only
    org.mockito.Mockito#verifyNoMoreInteractions
    
    0 讨论(0)
  • 2021-02-12 20:46

    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.
    0 讨论(0)
  • 2021-02-12 20:48

    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)

    0 讨论(0)
  • 2021-02-12 20:48

    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.

    0 讨论(0)
  • 2021-02-12 20:51

    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)
        ...
    
    0 讨论(0)
  • 2021-02-12 20:55

    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();
        }
    }
    
    0 讨论(0)
提交回复
热议问题