Issue
I am curious about the best / recommended approach to follow when writing a unit test.
If I can easily create the specific values that would get passed for a function, should I create those in my unit tests and use them? Or can I use any()
to mock for all values?
class Foo {
bool func1(String abc, int xyz, Bar bar) {
// ...
}
}
If I have a class like this that I want to mock for a specific behavior, which is a better approach?
@Mock
Foo mockFoo;
-
Bar dummyBar = getTestBar(); when(mockFoo.func1("value1", 1, dummyBar)).thenReturn(true);
-
when(mockFoo.func1(anyString(), anyInt(), any())).thenReturn(true);
I am trying to identify when to use each. I feel using specific values will be better whenever possible and if it is simple to create those values. Use any()
only when it is not easy to create such objects. i.e. Say I am refactoring a codebase and I see almost all unit tests are using any()
even if I could use specific values. Will it be worth doing some cleanup on the code and make the unit tests use specific values?
Solution
For a function install(String id)
, any of the following are possible:
id
will be a random and unpredictable set of characters such thatanyString()
is the best you can do. If you were to pick a value, it risks the test failing at random, making the code brittle or flaky.id
should be"yourProgramName"
specifically, and any deviation should fail the test. This is whereeq
and raw values would be appropriate.id
should be"yourProgramName"
, but that's important to some test other than the one you're writing right now, so it should beeq
in theid
-validating test andanyString
here.
It is entirely up to you: You'll need to pick which parameters matter to your test, and whether your test errs on the side of brittle (failing when it should pass) or permissive (passing when it should fail).
As a side note, you can mix any combination of specific matchers like eq
and general matchers like anyString
, or you can use all real values that test equals
just like eq
; you just can't mix both styles in the same call.
/* Any mix of matchers is OK, but you can't mix unwrapped values. Use eq() instead. */
/* bad: */ when(mockFoo.func1( "example" , anyInt(), any())).thenReturn(true);
/* good: */ when(mockFoo.func1(eq("example"), anyInt(), any())).thenReturn(true);
/* Unwrapped values are OK as long as you use them for every parameter you pass. */
/* good: */ when(mockFoo.func1( "example" , 0 , bar1 )).thenReturn(true);
/* same: */ when(mockFoo.func1(eq("example"), eq(0), eq(bar1))).thenReturn(true);
Answered By - Jeff Bowman
Answer Checked By - David Goodson (JavaFixing Volunteer)