Correct way to use Mockito for JdbcOperation - junit

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);

Related

Mockito InvalidUseOfMatchersException despite using only matchers (and hint seems to mention wrong number of parameters)

I ran into a well-known InvalidUseOfMatchersException even though I was using all matchers.
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
3 matchers expected, 2 recorded:
-> at com.spotify.adaccountservice.utils.RoleUtilsTest.test_addOrRemoveRole_AddUserToAdAccount(RoleUtilsTest.java:179)
-> at com.spotify.adaccountservice.utils.RoleUtilsTest.test_addOrRemoveRole_AddUserToAdAccount(RoleUtilsTest.java:180)
I know we don't like screenshots of code here, but I want to convince that it's indeed happening at these line numbers:
And here's the actual method:
So it was kind of strange. Why is it expecting 3 matchers, when the method has 4 parameters? And why is it only "recording" 2 of them, when I'm using eq() for all of them?
Self-answering, as the error misdirected me. (Or, maybe someone can explain why it was actually accurate.)
Turns out it was because one of the variables in my 3rd argument, portcullisUtils, was a mock object that I forgot to stub for getAdAccountRoleId(...).
I suppose the program can't really tell that of course I didn't mean to match against such an abstraction, and did something weird.
Will accept whoever's answer can explain why these particular error messages.

Junit using eq() argument matcher vs passing string directly

What is the use of eq() argument matcher if passing the string directly will do the same thing.
e.g. the behaviour of
when(method.foo("test")).thenReturn("bar");
is similar to
when(method.foo(ArgumentMatcher.eq("test"))).thenReturn("bar");
There are more ArgumentMatchers than eq(). Another popular one is any(), but there are many more ArgumentMatchers. They are generally used together to help identify the correct value for the test case. You may not want to check all args in all tests. For example, if there were more params in your code.
when(method.foo(eq("test"), any(Test.class), isNull()).thenReturn("bar");
I agree that eq() seems redundant, but the trick is if one argument uses a matcher all must, so if you want to use one any() you can no longer just put an unwrapped String argument.

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

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.

Calling mock method instead of real method with Mockito

I have a method which needs to be called instead of the real method.
Instead I get an exception. Can somebody please help me with right way to call the alternate method through mockito ?
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 4 recorded.
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"));
//Code starts here
class A{
public realMethod(String s, Foo f){
}
}
class B {
public mockMethod(String s, Foo f) {
}
}
class UnitTestClass{
ClassA mock = new ClassA();
mock.when(realMethod(any(String.class), any(Foo.class))).thenReturn(mockMethod(any(String.class),any(Foo.class));
}
You are getting mocking wrong.
Here:
thenReturn(mockMethod(any(String.class),any(Foo.class));
That simply doesn't make sense.
Mocking works like this:
you create a mock object of some class, like A mock = mock(A.class)
you specify interactions on that mock object
Your code implies that you think that these specifications are working like "normal" code - but they do not!
What you want to do: when some object is called with certain parameters, then return the result of another method call.
Like in:
when(a.foo(x, y)).thenReturn(b.bar(x, y))
That is what want you intend to do. But thing is: it isn't that easy. You can't use the any() matcher in thee thenReturn part in order to "provide" the arguments that were passed in the when() call before! It is that simply.
Mocking should be within a specific unit test to get a specific result.
Meaning: you are not writing an ordinary program where it would make any sense to "forward" parameters to another call. In other words; your code should more look like:
when(mock.realMethod("a", someSpecificFoo)).thenReturn(mockMethod("a", someSpecificFoo))
That is the only thing possible here.
Beyond that, you might want to look into a Mockito enter link description here instead.
Long story short: it simply looks like you don't understand how to use mocking frameworks. I suggest that you step back and read/work various tutorials. This is not something you learn by trial and error.

Junit assertEquals on objects with double fields

I have two Lists of Objects. These objects reference other objects which in turn contain doubles. I want to use assertEquals to test that the two objects are the same. I have verified by hand that they are, but assertEquals is still returning false. I think the reason is because the doubles are not the same because of precision issues. I know that I can solve this problem by drilling down to the double fields and using assertEquals(d1, d2, delta), but that seems cumbersome. Is there anyway to provide a delta to assertEquals (or another method), such that it can use that delta whenever it encounters doubles to compare?
Hamcrest matchers may make this a little easier. You can create a custom Matcher (or a FeatureMatcher - Is there a simple way to match a field using Hamcrest?), then compose it with a closeTo to test for doubles, and then use container matchers (How do I assert an Iterable contains elements with a certain property?) to check the list.
For example, to check for a list containing exactly one Thing, which has a getValue method returning approximately 10:
Matcher<Thing> thingWithExpectedDouble =
Matchers.<Thing>hasProperty("value", Matchers.closeTo(10, 0.0001));
assertThat(listOfItems, Matchers.contains(thingWithExpectedDouble));