PowerMockito can't seem to match and overloaded method - mockito

I can't seem to overcome this problem. I'm trying to mock an overloaded method that takes 1 argument
class ClassWithOverloadedMethod {
private boolean isValid(ClassA a){
return true;
}
private boolean isValid(ClassB B){
return false;
}
}
Mock setup
ClassWithOverloadedMethod uut = PowerMockito.spy(new ClassWithOverloadedMethod());
PowerMockito.doReturn(true).when(uut, "isValid", Matchers.isA(ClassB.class));
but PowerMockito keeps returning this error
java.lang.NullPointerException
at java.lang.Class.isAssignableFrom(Native Method)
at org.powermock.reflect.internal.WhiteboxImpl.checkIfParameterTypesAreSame(WhiteboxImpl.java:2432)
at org.powermock.reflect.internal.WhiteboxImpl.getMethods(WhiteboxImpl.java:1934)
at org.powermock.reflect.internal.WhiteboxImpl.getBestMethodCandidate(WhiteboxImpl.java:1025)
at org.powermock.reflect.internal.WhiteboxImpl.findMethodOrThrowException(WhiteboxImpl.java:948)
at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:882)
at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:713)
at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:401)
at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:93)
I'm using PowerMockito 1.5 with Mockito 1.9.5

Try using one of the when() methods that accepts a Method object. You can use Whitebox to retrieve the method instance you want by specifying the parameter type which should get around your current issue.
So something like
Method m = Whitebox.getMethod(ClassWithOverloadedMethod.class, ClassB.class);
PowerMockito.doReturn(true).when(uut, m).withArguments(Matchers.any(ClassB.class));
See Also
http://powermock.googlecode.com/svn/docs/powermock-1.5.1/apidocs/org/powermock/api/mockito/expectation/PowerMockitoStubber.html#when(java.lang.Class,%20java.lang.reflect.Method)
http://powermock.googlecode.com/svn/docs/powermock-1.5.1/apidocs/org/powermock/reflect/Whitebox.html#getMethod(java.lang.Class,%20java.lang.Class...)

Related

ClassCastException on attempt to mock Querydsl SQLQueryFactory

Trying to mock SQLQueryFactory of Querydsl for DAO unit testing. Using Mockito's deep stub for the very first time.
Below is the minimal code which fails
#Test
void tryMockQueryDsl() {
SQLQueryFactory sql = Mockito.mock(SQLQueryFactory.class, Mockito.RETURNS_DEEP_STUBS);
Mockito.when(sql.select(ArgumentMatchers.<Expression<?>>any())
.from(ArgumentMatchers.<Expression<?>>any())
.fetchFirst()
).thenReturn(null);
}
with the following exception:
java.lang.ClassCastException: class com.querydsl.sql.ProjectableSQLQuery$MockitoMock$1584151766 cannot be cast to class com.querydsl.sql.SQLQuery (com.querydsl.sql.ProjectableSQLQuery$MockitoMock$1584151766 and com.querydsl.sql.SQLQuery are in unnamed module of loader 'app')
What can be the problem?
Mocks can not be cast. Instead of RETURN_DEEP_STUBS mock each method on its own and return a mocked instance of the expected class.
If you do not want to suppress the warnings you will get for not defining the generic types, you can use the #Mock annotation instead to create the mocks, like described here.
This example doesn't make much sense for a testcase (as it tests nothing), but its a showcase on how to avoid the exception.
#RunWith(MockitoJUnitRunner.class)
public class Test {
#Test
public void tryMockQueryDsl() {
ProjectableSQLQuery projectableQuery = Mockito.mock(ProjectableSQLQuery.class);
// not really needed as this is the default behaviour
Mockito.when(projectableQuery.fetchFirst()).thenReturn(null);
SQLQuery query = Mockito.mock(SQLQuery.class);
Mockito.when(query.from(ArgumentMatchers.<Expression<?>>any())).thenReturn(projectableQuery);
SQLQueryFactory sql = Mockito.mock(SQLQueryFactory.class);
Mockito.when(sql.select(ArgumentMatchers.<Expression<?>>any())).thenReturn(query);
Expression expr = Mockito.mock(Expression.class);
sql.select(expr).from(expr).fetchFirst();
}
}

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

Mock Void type in Mockito

Say Foo is the class we mock and Foo has a method named Foo.bar() which returns type Void (not void). How can we use Mockito to mock this method?
Not sure whether returning null in this case would be the best solution.
Because Void is final and not instantiable, there is no instance you could ever return. In production, that method can only return null (if it returns at all), and that should hold true in your tests as well.
Note that Mockito will return null by default for methods that return Object instances other than collections and primitive wrappers, so you should only need to stub a method that returns Void if you need to override a spied method:
// Spy would have thrown exception
// or changed object state
doReturn(null).when(yourSpy).someMethodThatReturnsVoid();
Or throw an exception:
// Throw instead of returning null by default
when(yourMock.someMethodThatReturnsVoid()).thenThrow(new RuntimeException());
Or react with an Answer:
when(yourMock.someMethodThatReturnsVoid()).thenAnswer(new Answer<Void>() {
#Override public void answer(InvocationOnMock invocation) {
// perform some action here
return null;
}
}

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

Resources