18

How can I stub a method such that when given a value I'm not expecting, it returns a default value?

For example:

Map<String, String> map = mock(Map.class);
when(map.get("abcd")).thenReturn("defg");
when(map.get("defg")).thenReturn("ghij");
when(map.get(anyString())).thenReturn("I don't know that string");

Part 2: As above but throws an exception:

Map<String, String> map = mock(Map.class);
when(map.get("abcd")).thenReturn("defg");
when(map.get("defg")).thenReturn("ghij");
when(map.get(anyString())).thenThrow(new IllegalArgumentException("I don't know that string"));

In the above examples, the last stub takes precedence so the map will always return the default.

Alex Spurling
  • 54,094
  • 23
  • 70
  • 76

3 Answers3

31

The best solution I have found is to reverse the order of the stubs:

Map<String, String> map = mock(Map.class);
when(map.get(anyString())).thenReturn("I don't know that string");
when(map.get("abcd")).thenReturn("defg");
when(map.get("defg")).thenReturn("ghij");

When the default is to throw an exception you can just use doThrow and doReturn

doThrow(new RuntimeException()).when(map).get(anyString());
doReturn("defg").when(map).get("abcd");
doReturn("ghij").when(map).get("defg");

https://static.javadoc.io/org.mockito/mockito-core/2.18.3/org/mockito/Mockito.html#12

Alex Spurling
  • 54,094
  • 23
  • 70
  • 76
  • 1
    Thanks for the thorough answer including `doReturn()`. (`doThrow()` is unnecessary in this case except for consistency.) – David Sep 01 '15 at 17:23
  • The stub ordering thing is called out in the same documentation you referenced there: https://www.javadoc.io/doc/org.mockito/mockito-core/2.18.3/org/mockito/Mockito.html#12 — "Last stubbing is more important - when you stubbed the same method with the same arguments many times." – M. Justin May 26 '22 at 01:57
3
when(map.get(anyString())).thenAnswer(new Answer<String>() {
    public String answer(Invocation invocation) {
        String arg = (String) invocation.getArguments()[0];
        if (args.equals("abcd")
             return "defg";
        // etc.
        else
             return "default";
             // or throw new Exception()
    }
});

It's kind of a roundabout way to do this. But it should work.

shoebox639
  • 2,312
  • 15
  • 14
2

You can use:

Map<String, String> map = mock(Map.class, new Returns("I don't know that string"));
when(map.get("abcd")).thenReturn("defg");
when(map.get("defg")).thenReturn("ghij");
Guillaume Perrot
  • 4,278
  • 3
  • 27
  • 37