I am writing unit test case for update method for book.
@Test
void testUpdateBook() {
//initializing the bookId here
givenBookId();
//initializing the book here
givenBook();
givenMock();
//call the updateBook method
whenUpdateBookRequested();
thenVerifyBook();
}
givenMock() {
when(bookRepository.updateBook(bookId,any()).thenReturn(Optional.ofNullable(expectedBook));
}
Every other method is working fine but givenMock() is producing error:
Invalid use of argument matchers. 2 matchers expected, 1 recorded
And if I write the same method like below, then test is running successfully but I am not able to understand the meaning of eq(). Can someone please explain the difference between the previous and the modified method?
givenMock(){
when(bookRepository.updateBook(eq(bookId),any()).thenReturn(Optional.ofNullable(expectedBook));
}
CodePudding user response:
This is directly related to the way Mockito is implemented.
When you stub a method Mockito expects you to pass the argument values or matchers. There's a very important detail you should take into account. The arguments should be either all exact values or all matchers.
Look at these examples:
when(repository.updateBook(bookId, any()).thenReturn(something); // error
when(repository.updateBook(any(), someBook).thenReturn(something); // error
when(repository.updateBook(bookId, someBook).thenReturn(something); // valid
when(repository.updateBook(eq(bookId), any()).thenReturn(something); // valid
when(repository.updateBook(any(), eq(someBook)).thenReturn(something); // valid
when(repository.updateBook(any(), any()).thenReturn(something); // valid
The error message tells you exactly this. Mockito expected both arguments to be matchers, but instead it found only one.
Invalid use of argument matchers. 2 matchers expected, 1 recorded
CodePudding user response:
As ETO described, and as the Mockito documentation describes:
Warning:
If you are using argument matchers, all arguments have to be provided by matchers.
I have a deeper write-up in the question How do Mockito matchers work?, but in short, calls to Matchers work via side effects. When you call any()
or eq(bookId)
, Mockito returns a dummy value like null
or 0
and saves the Matcher details ("any" or "equals zero") onto its stack. Consequently, when Mockito sees the call to when
, there should be exactly 0 matchers (use equality) or 2 matchers (use matchers) on the stack.
For a call like when(yourMock).method(0, anyInt()).thenVerb(...)
, Mockito can't tell which of the two integer parameters is supposed to be exactly zero and which of the parameters is supposed to be any value, so it throws the error you see. eq
is the default behavior if you don't use matchers, so you may rarely see eq
unless you're being extra-explicit or if you are mixing eq
-style matching with other matchers like any
.