InvalidUseOfMatchersException : anyList() to match list of string causes exception - junit

I want to test a method which accepts list of string, makes a database call and returns list of entities.
EmployeeServiceTest
when(repository
.findByMessageTypeAndStatusAndMobileInOrderByCreatedDate("confirmed",
"received", anyList(), new PageRequest(0, 1000)))
.thenReturn(employeeEntities);
It gives below exception. matching the stringList with anyList() seems to be causing exception.
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
anyList() to match List of string is causing the exception. any idea why the exception is caused?

Probably your employeeService does not contain a mocked EmployeeService.
Create it by calling
EmployeeService employeeService = mock(EmployeeService.class)
instead of instantiating the real class (do not use new EmployeeService() here).
Update after the question has been extended:
You are mixing how arguments are matched: the first, second and fourth parameter are plain objects but the third parameter is a matcher.
If you verify one argument with a matcher, you have to use them for every argument.
There are matchers which are not wildcards but check whether the argument is equal to a fixed value: wrap your other arguments in the eq matcher:
when(repository .findByMessageTypeAndStatusAndMobileInOrderByCreatedDate(
eq("confirmed"),
eq("received"),
anyList(),
eq(new PageRequest(0, 1000))
)).....
Notice you have to implement a proper equals method in the class PageRequest. Otherwise org.mockito.Matchers.eq cannot compare the parameters successfully.

Related

Correct way to use Mockito for JdbcOperation

I am new to Mockito and trying to cover following source code:
jdbcOperations.update(insertRoleQuery,new Object[]{"menuName","subMenuName","subSubMenuName","aa","bb","cc","role"});
In this query is taking 7 string parameters. I have written the mockito test case for the code and it's also covering the source code but I am not sure whether it's the correct way or not.
when(jdbcOperations.update(Mockito.anyString(), new Object[]{Mockito.anyString(),Mockito.anyString(),Mockito.anyString(),Mockito.anyString(),Mockito.anyString(),Mockito.anyString(),Mockito.anyString()})).thenThrow(runtimeException);
Please suggest if i am doing it right way or not.
Thanks
As per the docs, you can either use exact values, or argument matchers, but not both at the same time:
Warning on argument matchers:
If you are using argument matchers, all arguments have to be provided
by matchers.
If you do mix them, like in your sample, mockito will complain with something similar to
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
-> at MyTest.shouldMatchArray(MyTest.java:38)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more info see javadoc for Matchers class.
In your case you don't seem to care about the array contents, so you can just use any():
when(jdbcOperation.update(anyString(), any())).thenThrow(runtimeException);
If you want to at least check the number of parameters, you can use either
org.mockito.Mockito's argThat(argumentMatcher):
when(jdbcOperation.update(anyString(), argThat(array -> array.length == 7))).thenThrow(runtimeException);
org.mockito.hamcrest.MockitoHamcrest's argThat(hamcrestMatcher):
when(jdbcOperation.update(anyString(), argThat(arrayWithSize(7)))).thenThrow(runtimeException);
If you're interested in matching certain values, you can use AdditionalMatchers.aryEq(expectedArray), or just Mockito.eq(expectedArray) which has a special implementation for arrays, but I fell that the first one expresses your intent in a clearer way.
when(jdbcOperation.update(anyString(), aryEq(new Object[]{"whatever"}))).thenThrow(runtimeException);

mockito throwing InvalidUseOfMatchersException

My getUserDetails class take User(custome class) and string as arguments and return User. If I use Mockito matcher as below:
when(authService.getUserDetails(any(User.class),anyString())).thenReturn(any(User.class));
It gives me InvalidUseOfMatchersException 2 matchers expected, 3 found. Can't I use the above expression?
Matchers are not used for returning.
.thenReturn(any(User.class));
You have to return something tangible here. Matchers are just for matching up input so that you can dictate what is returned when certain input is provided. You still need to have a real output to return.
You should pass instance of User to thenReturn, not matcher. That User instance will be returned when authService.getUserDetails is invoked.
This code will work:
User user=new User();
when(authService.getUserDetails(any(User.class),anyString())).thenReturn(user));
As there should be a value and not type in thenReturns()

Mockito - You cannot use argument matchers outside of verification or stubbing - have tried many things but still no solution

I have the following piece of code:
PowerMockito.mockStatic(DateUtils.class);
//And this is the line which does the exception - notice it's a static function
PowerMockito.when(DateUtils.isEqualByDateTime (any(Date.class),any(Date.class)).thenReturn(false);
The class begins with:
#RunWith(PowerMockRunner.class)
#PrepareForTest({CM9DateUtils.class,DateUtils.class})
And I get org.Mockito.exceptions.InvalidUseOfMatchersException...... You cannot use argument matchers outside of verification or stubbing..... (The error appears twice in the Failure Trace - but both point to the same line)
In other places in my code the usage of when is done and it's working properly. Also, when debugging my code I found that any(Date.class) returns null.
I have tried the following solutions which I saw other people found useful, but for me it doesn't work:
Adding
#After
public void checkMockito() {
Mockito.validateMockitoUsage();
}
or
#RunWith(MockitoJUnitRunner.class)
or
#RunWith(PowerMockRunner.class)
Change to
PowerMockito.when(new Boolean(DateUtils.isEqualByDateTime(any(Date.class), any(Date.class)))).thenReturn(false);
Using anyObject() (it doesn't compile)
Using
notNull(Date.class) or (Date)notNull()
Replace
when(........).thenReturn(false);
with
Boolean falseBool=new Boolean(false);
and
when(.......).thenReturn(falseBool);
As detailed on the PowerMockito Getting Started Page, you'll need to use both the PowerMock runner as well as the #PrepareForTest annotation.
#RunWith(PowerMockRunner.class)
#PrepareForTest(DateUtils.class)
Ensure that you're using the #RunWith annotation that comes with JUnit 4, org.junit.runner.RunWith. Because it's always accepted a value attribute, it's pretty odd to me that you're receiving that error if you're using the correct RunWith type.
any(Date.class) is correct to return null: Rather than using a magic "matches any Date" instance, Mockito uses a hidden stack of matchers to track which matcher expressions correspond to matched arguments, and returns null for Objects (and 0 for integers, and false for booleans, and so forth).
So in the end,what worked for me was to export the line that does the exception to some other static function. I called it compareDates.
My implementation:
In the class that is tested (e.g - MyClass)
static boolean compareDates(Date date1, Date date2) {
return DateUtils.isEqualByDateTime (date1, date2);
}
and in the test class:
PowerMockito.mockStatic(MyClass.class);
PowerMockito.when(MyClass.compareDates(any(Date.class), any(Date.class))).thenReturn(false);
Unfortunately I can't say I fully understand why this solution works and the previous didn't.
maybe it has to do with the fact that DateUtils class is not my code, and I can't access it's source, only the generated .class file, but i'm really not sure about it.
EDIT
The above solution was just a workaround that did not solve the need to cover the DateUtils isEqualByDateTime call in the code.
What actually solved the real problem was to import the DateUtils class which has the actual implementation and not the one that just extends it, which was what I imported before.
After doing this I could use the original line
PowerMockito.mockStatic(DateUtils.class);
PowerMockito.when(DateUtils.isEqualByDateTime (any(Date.class),any(Date.class)).thenReturn(false);
without any exception.
I had a similar problem with TextUtils in my Kotlin Test Class
PowerMockito.`when`(TextUtils.isEmpty(Mockito.anyString())).thenReturn(true)
Resolved it by adding below code on top of my Test Class
#PrepareForTest(TextUtils::class)
and called mockStatic this before PowerMockito.`when`
PowerMockito.mockStatic(TextUtils::class.java)

Test Failure Message in mockito : Argument(s) are different! Wanted:

I am testing a Restful endpoint in my JUnit and getting an exception as below in the
list which is present as an argument inside the save method,
**"Argument(s) are different! Wanted:"**
save(
"121",
[com.domain.PP#6809cf9d,
com.domain.PP#5925d603]
);
Actual invocation has different arguments:
save(
"121",
[com.domain.PP#5b6e23fd,
com.domain.PP#1791fe40]
);
When I debugged the code, the code broke at the verify line below and threw the
above exception. Looks like the arguments inside the "testpPList" within the save
method is different. I dont know how it becomes different as I construct them in my
JUNit properly and then RestFul URL is invoked.
Requesting your valuable inputs. Thanks.
Code:
#Test
public void testSelected() throws Exception {
mockMvc.perform(put("/endpointURL")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(testObject)))
.andExpect(status().isOk());
verify(programServiceMock, times(1)).save(id, testpPList);
verifyNoMoreInteractions(programServiceMock);
}
Controller method:
#RequestMapping(value = "/endpointURL", method = RequestMethod.PUT)
public #ResponseBody void uPP(#PathVariable String id, #RequestBody List<PPView> pPViews) {
// Code to construct the list which is passed into the save method below
save(id, pPList);
}
Implementing the Object#equals(Object) can solve it by the equality comparison. Nonetheless, sometimes the object you are validating cannot be changed or its equals function can not be implemented. For such cases, it's recommended using org.mockito.Matchers#refEq(T value, String... excludeFields). So you may use something like:
verify(programServiceMock, times(1)).save(id, refEq(testpPList));
Just wrapping the argument with refEq solves the problem.
Make sure you implement the equals method in com.domain.PP.
[Edit]
The reasoning for this conclusion is that your failed test message states that it expects this list of PP
[com.domain.PP#6809cf9d, com.domain.PP#5925d603]
but it's getting this list of PP
[com.domain.PP#5b6e23fd, com.domain.PP#1791fe40]
The hex values after the # symbol for each PP object is their hash codes. Because they are different, then it shows that they belong to different objects. So the default implementation of equals will say they're not equal, which is what verify() uses.
It's good practice to also implement hashCode() whenever you implement equals(): According to the definition of hashCode, two objects that are equal MUST have equal hashCodes. This ensures that objects like HashMap can use hashCode inequality as a shortcut for object inequality (here, placing objects with different hashCodes in different buckets).

mockito when thenReturn does not return stubbed array list

List<Populate> fullAttrPopulateList = getFullAtrributesPopulateList(); //Prepare return list
when(mockEmployeeDao.getPopulateList(null)).thenReturn(fullAttrPopulateList);
MyDTO myDto = testablePopService.getMyPopData(); //Will call mockEmployeeDao.getPopulateList(null)
//verify(mockEmployeeDao,times(1)).getPopulateList(null);
assertEquals(fullAttrPopulateList.size(), myDto.getPopData().size()); //This fails because myDto.getPopData().size() returns 0
As you can see testablePopService.getMyPopData() calls mockEmployeeDao.getPopulateList(null) but when I debug it a zero sized list returns instead of the stubbed array list which is prepared by getFullAtrributesPopulateList();
If I uncomment the verify statement, it passes the test meaning getPopulateList(null) behavior does get called.
Can anyone give me some advice why my stubbed array list cannot be returned even it is verified the expected behavior happened? How come an empty array list returns rather than a null if I did something wrong?
First, check that the method is non-final and visible throughout its hierarchy. Mockito can have trouble mocking methods that are hidden (e.g. overriding a package-private abstract class's implementation); also, Mockito is entirely unable to mock final methods, or even to detect that the method is final and warn you about it.
You may also want to check that your call is using the overload you expect. Mockito's default list return value is an empty list, so you may simply stubbing one method and seeing the default value for another. You can see which method interactions Mockito has added by adding a call to verifyZeroInteractions temporarily, and Mockito will throw an exception with a list of calls that mock has received. You could also add verifyNoMoreInteractions, and even leave it in there, at the expense of test brittleness (i.e. the test breaks when the actual code continues to work).