Issue with Mockito.Any for overloaded methods - mockito

I have two methods in my Java class as below
Method 1:
public ResponseEntity<T> callMethod(String param1,Map<String, String> param2, Object param3,HttpMethod param4,Class<T> param5)
Method 2
public ResponseEntity<T> callMethod(Map<String, String> param1, Object param2,
HttpMethod param3, Map<String, ?> param4,
final Class<T> param5) {
I have written a unit test case where when i try to call the method as below
callMethod(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(),
eq(ServiceResponse.class))).thenReturn(responseEntity)
it fails with the below error
reference to callMethod is ambiguous
both method callMethod
(java.util.Map<java.lang.String,java.lang.String>,B,org.springframework.http.HttpMethod,java.util.Map<java.lang.String,?>,java.lang.Class)
and method
callMethod(java.lang.String,java.util.Map<java.lang.String,java.lang.String>,B,org.springframework.http.HttpMethod,java.lang.Class)
match
How can this be resolved. There are many unit test cases and i want to fix the class than the unit test cases. Is there a way?

Yes, you can put types in the any() like any(MyClass.class) there are also some built in ones. If you want to call your first method you can use the anyString() and anyMap() ones.
callMethod(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.any(HttpMethod.class), eq(ServiceResponse.class))).thenReturn(responseEntity)

Related

Changing Object.toString() dynamically in Groovy has no effect when calling Integer.toString()

I injected overridden method toString into Object.metaClass:
Object.metaClass.toString ={
System.out.println("the string is $delegate")
}
and I thought that following code will execute this method:
1500.toString()
But it didn't not,nothing was printed to the console. That is what exactly confuses me: if something goes bad, then an error is to throw out; if Object.metaClass.toString is found and invoked, then the message will turn up, but why it is not working? What happened inside?
This behavior is correct, because java.lang.Integer overrides Object.toString() with its own implementation. If your assumption was correct then it would mean that you can break overridden method by forcing to use an implementation from parent class.
Consider following Groovy script:
Object.metaClass.toString = {
System.out.println("the string is $delegate")
}
class GroovyClassWithNoToString {}
class GroovyClassWithToString {
#Override
String toString() {
return "aaaa"
}
}
new GroovyClassWithNoToString().toString()
new GroovyClassWithToString().toString()
1500.toString()
Runtime.runtime.toString()
When you run it you will see something like:
the string is GroovyClassWithNoToString#3a93b025
the string is java.lang.Runtime#128d2484
You can see that GroovyClassWithNoToString.toString() called Object.toString() method and its modified version, also Runtime.toString() calls Object.toString() - I picked this class as an example of pure Java class that does not override toString() method.
As you can see overriding toString() method from Object level makes sense for classes that base on Object.toString() implementation. Classes that provide their own implementation of toString() wont use your dynamically modified method. It also explains why following code works:
Object.metaClass.printMessage = {
System.out.println("Hello!")
}
1500.printMessage()
In this example we are adding a new method called printMessage() to Object class and all classes that don't override this method will use this dynamic method we just created. Integer class does not have method like that one so it's gonna print out:
Hello!
as expected.
Also keep in mind that toString() should return a String and it's better to not print anything to output inside this method - you can end up with nasty StackOverflowError caused by circular calls to toString() method.
UPDATE: How toString() method is being picked by Groovy runtime?
Let me show you under the hood what happens when we call following script:
Object.metaClass.toString = {
System.out.println("Hello!")
}
1500.toString()
and let's see what does Groovy during the runtime. Groovy uses Meta Object Protocol (MOP) to e.g. invoke any method called in a Groovy code. In short, when you call any Java or Groovy method it uses MOP as an intermediate layer to find an execution plan for a method - call it directly or use e.g. a method that was injected dynamically.
In our case we use plain Java class - Integer. In this case Groovy will create an instance of PojoMetaMethodSite class to meta class implementation for Java class - an Integer. Every meta method is executed using one of the Groovy groovy.lang.MetaClass implementation. In this case groovy.lang.MetaClassImpl is being used. One of the last methods that picks a method to execute is MetaClassImpl.getMethodWithCachingInternal(Class sender, CallSite site, Class [] params). If you put a breakpoint in the beginning of this method and run a script with a debugger, you will see that this method is executed with following parameters:
In line 1331 you can see that helper method called chooseMethod(e.name, methods, params) is being used:
cacheEntry = new MetaMethodIndex.CacheEntry (params, (MetaMethod) chooseMethod(e.name, methods, params));
This method is responsible for picking the right method to execute when we try to invoke toString() on Integer object. Let's get there and see what happens. Here is what this method implementation looks like:
/**
* Chooses the correct method to use from a list of methods which match by
* name.
*
* #param methodOrList the possible methods to choose from
* #param arguments
*/
protected Object chooseMethod(String methodName, Object methodOrList, Class[] arguments) {
Object method = chooseMethodInternal(methodName, methodOrList, arguments);
if (method instanceof GeneratedMetaMethod.Proxy)
return ((GeneratedMetaMethod.Proxy)method).proxy ();
return method;
}
Source: https://github.com/apache/groovy/blob/GROOVY_2_4_X/src/main/groovy/lang/MetaClassImpl.java#L3158
Now let's see what parameters are received when we call our script:
What is most interesting in our case is the first element of methodOrList.data. It's a method object of:
public java.lang.String java.lang.Integer.toString()
which is the method toString() that Integer class overrides from its parent class. Groovy runtime picks this method, because it is the most accurate from the runtimes point of view - it is the most specific method for Integer class provided. If there is no toString() method overridden at the class level (e.g. Runtime class example I mentioned earlier) then the best candidate for invoking toString() method is a ClosureMetaMethod provided by us in Object.metaClass.toString = .... I hope it gives you a better understanding of what happens under the hood.
I don't think you can override the Object.toString() that way.
But this works:
Integer.metaClass.toString = { ->
System.out.println("the string is $delegate")
}
https://groovyconsole.appspot.com/script/5077208682987520

how to match the String... use Mockito and PowerMock

I am studying Mockito and PowerMock recently.
I ran into the following problem
//This method belongs to the Messages class
public static String get(Locale locale, String key, String... args) {
return MessageSupplier.getMessage(locale, key, args);
}
//the new class
#RunWith(PowerMockRunner.class)
#PowerMockIgnore( {"javax.management.*"})
#PrepareForTest({Messages.class, LocaleContextHolder.class})
public class DiscreT {
#Test
public void foo() {
PowerMockito.mockStatic(LocaleContextHolder.class);
when(LocaleContextHolder.getLocale()).thenReturn(Locale.ENGLISH);
PowerMockito.mockStatic(Messages.class);
when(Messages.get(Mockito.any(Locale.class),Mockito.anyString(), Mockito.any(String[].class)))
.thenReturn("123156458");
System.out.print(Messages.get(LocaleContextHolder.getLocale(), "p1"));
System.out.print(Messages.get(LocaleContextHolder.getLocale(), "p1", "p2"));
}
}
the result : null 123156458
why? and how to match the String...
In your first System.out.print statement, you use 2 arguments for the Messages.get method. This is one of the method's overloads that you have not mocked. That's why it returns null. Note that object mocks that have not had their behavior mocked will return null by default.
You would have to mock the Messages.get(Locale, String) method as well if you want it to work
when(Messages.get(Mockito.any(Locale.class),Mockito.anyString()))
.thenReturn("123156458");
Remember, the fact that you have mocked the method that takes the most arguments doesn't mean Mockito understands and mocks the rest of the overloads! You have to mock them as well.
There is no way to mock a method once and automatically mock all of its overloads as far as I know however, there is a way to create a mock object and configure a default response for all of its methods. Check out http://www.baeldung.com/mockito-mock-methods#answer

Mocking static class in Mockito

I have something like the following:
public class Foo {
public static String getValue(String key) {
return key + "_" + System.currentTimeMillis();
}
}
Now I need to have a test case for it and here is how I attempted:
#Test
public void testFoo() {
PowerMockito.mockStatic(Foo.class);
PowerMockito.when(Foo.getValue("123")).thenReturn("abcd");
PowerMockito.verifyStatic();
}
When I run the test case, I get this:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
at org.powermock.api.mockito.PowerMockito.when(PowerMockito.java:495)
Am I doing anything wrong?
Please advise.
Can you confirm that you've added a #PrepareForTest(Foo.class) annotation onto your test class as listed on the PowerMock site, and that you're using the PowerMockRunner JUnit4 runner?
Static methods are invoked with static dispatch, not dynamic dispatch using Java's normal polymorphism and method overrides. To replace the implementation, PowerMock needs to load a replacement class before the test starts running, and the runner and annotation make that happen.

Caused InvalidUseOfMatchersException for clearly mocked class

I got error while running JUnit test with Mockito's matcher
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 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"));
Here is source code.
class A
{
public String getField()
{
return "hi";
}
}
#Test
public void testA()
{
final A a = mock(A.class);
when(a.getField()).thenReturn(Matchers.any(String.class));
a.getField();
}
What is problem here? Please open my eyes!
You are using an argument matcher: Matchers.any(String.class). An argument matcher is not intended to be used as a return a value of a stubbed method.
An argument matcher should be used when you need to customize the way a method is stubbed :
when(a.sayHello(Matchers.any(String.class))).thenReturn("Hello");
In your example, you must return an instance of String and not a matcher :
when(a.getField()).thenReturn("theFieldValue");
You have made the classic error of mocking the class that you're trying to test. The whole point of mocking is that you remove other classes from consideration by your test. So if you're testing a class A that uses an object of class B in some way, you might make a mock of class B. But you wouldn't mock the class that you're actually testing, because then you are no longer testing the class, but testing the mocking framework.
In order to test the method you've supplied, it doesn't make sense to use Mockito at all; because there's no additional class that you want to remove from consideration by your test. The only class is A - the one you're testing.
Your test should just be the following
public class TestA {
private A toTest = new A();
#Test
public void getFieldReturnsHi() {
assertEquals("Hi", toTest.getField());
}
}

Mockito verify method was called with set, that contains specific value

I want to be sure that mocked is called with specific set of strings as parameter.
For example, I have the following code:
public class SomeLogic {
#Autowired
private SpecificService specificService;
public void action() {
Set<String> args = fillArgsMethod();
specificService.handleArgs(args);
}
}
And my current try to test it is the following
#Mock
private SpecificService specificService
#InjectMocks
private SomeLogic someLogic;
#Test
public void testAction() {
someLogic.action();
verify(specificService).handleArgs(anySet());
}
But I want to be sure, that handleArgs() will receive the exact set of strings, that I expect. How can I modify verifying to check that handleArgs is called with set "first","second"?
Thanks
Isah gave a valid answer, but I want to turn your attention to a more general feature of Mockito which is ArgumentCaptor
In you case you would do something along the following lines:
Class<HashSet<String>> setClass = (Class<HashSet<String>>)(Class)HashSet.class;
ArgumentCaptor<Set<String>> setCaptor= ArgumentCaptor.forClass(setClass .class);
verify(specificService).create(setCaptor.capture());
HashSet<String> capturedSet = setCaptor.getValue();
//do whatever test you want with capturedSet
Prepare your Set parameters before calling the test method
#Test
public void testAction() {
Set<String> expectedParams = new HashSet(Arrays.asList("first", "second");
//call tested method
verify(specificService).handleArgs(expectedParams);
}
isah's solution is perfect for you if you want to confirm that the set contains exactly the two items you specify; Mockito compares using .equals by default, and Set.equals is defined as refer to equal elements in any order.
For a more-flexible "contains" test that matches your question title, that allows for set members beyond your expected values, you can also use the Hamcrest contains matcher:
someLogic.action();
verify(specificService).handleArgs(argThat(contains("first", "second")));
At least, that's how it should look. Unfortunately, argThat infers its return type from the Matcher, which infers its return type from the arguments, so Java assumes your first argument is not a Set<String> but a Iterable<capture#1-of ? extends String>. You'll need to cast explicitly and suppress warnings to get it to work:
// requires #SuppressWarnings("unchecked")
verify(specificService).handleArgs(
(Set<String>) argThat(contains("first", "second")));

Resources