Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
383 views
in Technique[技术] by (71.8m points)

java - How do I get Mockito mocks to cause a failure when unexpected calls are made?

I have some mock objects that are probably going to get passed around a bit and might end up being fairly complex.

I'd like to either have Mockito output a log for each call made to a mock or I'd like it to fail whenever an unexpected call is made so I can iterate through those calls and set up appropriate responses.

How can I accomplish this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The most-idiomatic way of doing this is with verifyNoMoreInteractions, as in Mockito docs #8:

//interactions
mock.doSomething();
mock.doSomethingUnexpected();

//verification
verify(mock).doSomething();

//following will fail because 'doSomethingUnexpected()' is unexpected
verifyNoMoreInteractions(mock);

I say "most-idiomatic" above because that method has its own warning label, which links to the blog post "Should I worry about the unexpected?" by Mockito originator Szczepan Faber.

verifyNoMoreInteractions() is not recommended to use in every test method. verifyNoMoreInteractions() is a handy assertion from the interaction testing toolkit. Use it only when it's relevant. Abusing it leads to overspecified, less maintainable tests.

In short, you should have a very clear reason to check what your dependency is not doing or what your system-under-test is not calling, as opposed to what they are doing and calling. You might use verifyNoMoreInteractions for an RPC object, if you want to avoid unnecessary RPC calls, but not (say) a calculator with no side effects. Even better is to specify your exact requirements with never() or times(int) as parameters to verify.


That said, there are two even-less-idiomatic ways of doing this:

  • You can take an overall log of calls made using mockingDetails(Object) and iterating through getInvocations(). That should reflectively give you a whole list of the invocations. I have a hard time imagining how this would be useful in a test, but it might be useful in cleaning up a nebulous or poorly-documented existing system.

  • You can make the mock's default action to throw an exception, which means that if anyone calls something that you haven't stubbed, the test will immediately fail.

    // untested pseudocode
    YourObject yourObject = Mockito.mock(YourObject.class, withSettings()
        .defaultAnswer(invocation -> {
          throw new UnsupportedOperationException(invocation.toString());
        }));
    

    Sure, that'd work, but you'd not only be violating one of Mockito's core principles (mocks are nice by default, using EasyMock's definition of "nice"), but you'd also force yourself to only stub using doVerb (doReturn, doAnswer, etc) because calls to when(yourObject.doAnything()) would necessarily throw that exception before the call to when would even run.

    Developers who are familiar with Mockito would likely say that this exception-prone cure is worse than the disease, and may be useful only for temporarily diagnosing the most tangled legacy code.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...