1

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;
  1. Bar dummyBar = getTestBar();
    when(mockFoo.func1("value1", 1, dummyBar)).thenReturn(true);
    
  2. 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?

SyncMaster
  • 9,754
  • 34
  • 94
  • 137
  • 2
    that depends on what you want to be tested. do you want to test for specific values? do you just want to test no matter what call? – Stultuske Oct 17 '22 at 07:52
  • If I have an option to use a specific value, in those cases which would be a better option? – SyncMaster Oct 17 '22 at 08:03
  • if you are testing for a specific scenario, use the specific values. That way, if your code does something unexpected and uses other params than the ones you expect, you'll know – Stultuske Oct 17 '22 at 08:04
  • Of course 1. is "better", more exact (especially in a complex test context/with many tests) 2. can be sufficient (quicker, simpler...without "dirtying" the context!??) In any case: you cannot mix both approaches (in one `when`)..so sometimes you just *have to* use "any"... – xerx593 Oct 17 '22 at 08:05
  • @xerx593 sure you can mix, no? `when(mockFoo.func1(eq("value1"), eq("1"), any(Bar.class)).thenReturn(true);` – knittl Oct 17 '22 at 08:20
  • ..runtime exception,@knittl (with detailed description...https://stackoverflow.com/a/63485861/592355) (the last time I tried this, maybe newer Mockito can do it... [nope, still so](https://github.com/mockito/mockito/issues/1398)!) – xerx593 Oct 17 '22 at 08:22
  • 1
    @xerx593 Using the `eq` matcher is not the same as using raw values. Maybe we were both saying different things :) Nevertheless, it is still possible to match some specfic values while ignoring other parameters' values. – knittl Oct 17 '22 at 10:05

1 Answers1

1

For a function install(String id), any of the following are possible:

  • id will be a random and unpredictable set of characters such that anyString() 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 where eq 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 be eq in the id-validating test and anyString 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);
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251