简体   繁体   中英

Mockito, Usages of doNothing() When()

I'm new to Mockito, and I went over this example but there is one step that I do not understand when it calls doNothing() on the first line of the method:

@Test(expected = RuntimeException.class)
public void testConsecutiveCalls() throws Exception(){
  doNothing().doThrow(Exception.class).when(b).voidMethod();
  a.usesVoidMethod()
  verify(b).voidMethod();
  a.usesVoidMethod()
}

I do understand that when the first time voidMehtod() is called is returning nothing and in the second time it is giving an exception.

But if we remove the doNothing.doThrow(Exception.class).when(b).voidMethod(); , won't the test still be valid and will test what we want to test that the method throw an exception in the second time?

A few points, numbered just for ease of reference:

  1. The default behavior of a mock is to return an appropriate dummy value every time, often zero, null , or an empty string. The default behavior of a spy is to call the spy's real implementation. Of course, through parameters to @Mock or Mockito.mock , you can use an arbitrary Answer or any of Mockito's standard or additional answers.

  2. When multiple actions are given as a part of a chain, Mockito will do each action in sequence and forever repeat the final action.

     // calls to foo.bar() return 1, 2, 3, 3, 3... doReturn(1).thenReturn(2, 3).when(foo).bar();

    Note that this is within the same chain; the most-recently-defined matching chain wins, so separate statements wouldn't have the same effect.

     doReturn(1).thenReturn(2).when(foo).baz(); doReturn(3).thenReturn(4).when(foo).baz(); // calls return 3, 4, 4, 4... because the first chain is entirely overridden.
  3. doNothing , then, gets most of its value from either overriding default behavior or setting up an action in a chain .

So what the test is trying to do is to doNothing the first time such that the verification will succeed, and then doThrow the second time to satisfy the expected exception. Though a failed verify would (correctly) fail the test because Mockito's errors subclass Error and not Exception , you're right that a removal of the doNothing would still cause the test to pass by throwing the exception on the first call to a.usesVoidMethod() . Though this is fine enough for the test--after all, you can see the doNothing in the test itself--a more robust test might look like this:

@Test
public void testConsecutiveCalls() throws Exception(){
  doNothing().doThrow(SomeKnownException.class).when(b).voidMethod();
  a.usesVoidMethod();
  verify(b).voidMethod();
  try {
    a.usesVoidMethod();
    fail();
  } catch (SomeKnownException expected) { /* OK */ }
}

The doNothing method doesn't change the behaviour of a mocked' method, but the declaration of the doThrow does. If you have a spy and don't want a method to be executed, then does. If you have a spy and don't want a method to be executed, then doNothing` will change the behaviour.

This test is a poor test because (a) it doesn't make much sense, (b) it's testing two different things:

  1. a.usesVoidMethod() calls b.voidMethod() .
  2. When the dependency b throws a Exception , the object under test a throws a RuntimeException .

and (c), it's named incorrectly. It's testing the two things above independently, and the fact that they're consecutive calls is irrelevant.

If you remove the first line of this test method, then you remove the behavior of b that is being mocked. The test will then fail since a void method call on a mock will do nothing by default; ie, there will be no Exception from b , and thus no RuntimeException from a .

You are correct that if a was actually coded so that it threw a RuntimeException if it was called twice, then the mocking of b would not be needed. But that would be even less reasonable than it is already.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM