Mockito:how to match Class<T> [duplicate] - mockito

This question already has answers here:
Mockito: InvalidUseOfMatchersException
(8 answers)
Closed 5 years ago.
I have a question what about Argument Matcher.
class A(){
public B method(Class T,String str){}
}
I Stub the method and want pass the method.but .
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
A a = new A();
B b = new B();
Mockito.doReturn(b).when(a).method(argThat(new IsClass)), "111");
Class IsClass:
class IsClass extends ArgumentMatcher<Class> {
public boolean matches(Object obj) {
return true;
}
}
So, how should I do, can pass this method.Thankyou.

The full exception message should tell you what is wrong:
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
So, if your isClass() were a valid ArgumentMatcher then you would stub like this:
Mockito.doReturn(b).when(a).method(argThat(new IsClass()), eq("111"));
//note how the second parameter of method uses the argument matcher
//"eq" rather than the raw string "111"
Moreover, if you merely want to match "any class object" you can do it like this without having to write your own custom matcher:
Mockito.doReturn(b).when(a).method(any(Class.class), eq("111"));
Finally, you can only stub for mocks. So your test would have to include some setup code like this:
A a = Mockito.mock(A.class);
B b = new B();
Mockito.doReturn(...
Consider spending some time reading through the documentation to get a better handle of how to test using Mockito.

Related

Returning mock objects with Mockito using given arguments

For my JUnit Tests with Mockito, I am doing the following:
Mockito.lenient().when(tokenService.create(String id, Any)).thenReturn(new String (id))
Mockito.lenient().when(voucherRepo.findById(id String).thenReturn(new Voucher(id));
I would like to access the String id given to tokenService.create() and voucherRepo.findById() methods, create and then return mock objects using it. How it can be done?
Mockito.when(voucherRepo.findById(id)).thenReturn(new Voucher(id));
Your solution should work and is probably the preferred solution for any clear defined test.
As you know in your test what the exact id is, you can just return the specific object for it.
Another way to do this - for arbitrary strings - is using mockito's thenAnswer funtionality:
Mockito.when(voucherRepo.findById(Mockito.any(String.class))).thenAnswer(new Answer<Voucher>() {
#Override
public Voucher answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
String id = (String) args[0];
return new Voucher(id);
}
});
I am not sure what reason you have to do that in your test (as this a rather arbitrary defintion), but in doubt consider adding some more context to your question.

Getting InvalidUseOfMatchersException in the Mockito

I have written this java method:
public int run(String jobName) {
}
And I have written this test code:
#Test
public void testBatchStatusUpdateWithOneCompleteStatus() {
Set<BatchEntity> staleBatch = createStaleBatch();
Set<Integer> activeBatch = createActiveBatch();
when(batchRepository.findBatchIdByStateIn(
(Arrays.asList(BatchStates.IN_PROGRESS,
BatchStates.INTENT_MARKED)))).thenReturn(staleBatch);
when(listingRepository.findBatchId()).thenReturn(activeBatch);
Assert.assertEquals(batchStatusUpdate.run(Mockito.any(String.class)), 1);
Mockito.verify(batchRepository,Mockito.times(2)).save(Mockito.any(BatchEntity.class));
}
I am getting the below error when I run the
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 0 matchers expected, 1 recorded: at backgroundjob.BatchStatusUpdateTest.testBatchStatusUpdateWithOneCompleteStatus 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.
I am getting this error when run method has the string argument. When I remove the string argument from the run method the test case is passed.
Mockito.any() creates a matcher, which is used when specifying a mock or when verifying calls with Mockito.verify(). They do not make sense as an argument to the method you are testing though. Your call should be changed to use an actual string, for example Assert.assertEquals(batchStatusUpdate.run("some value"), 1); instead of Assert.assertEquals(batchStatusUpdate.run(Mockito.any(String.class)), 1);

Applying default groovy method parameter value when passing null

In Groovy, if I have:
def say(msg = 'Hello', name = 'world') {
"$msg $name!"
}
And then call:
say() // Hello world!
say("hi") // Hi world!
say(null) // null world!
Why is the last one getting interpreted literally as null and not applying the default value? Doesn't this defeat the purpose of default method argument values? I do get that passing null is different from not passing anything w/r/t argument length.
My problem here is that if I now have a method that takes a collection as an argument:
def items(Set<String> items = []) {
new HashSet<>(items)
}
This will throw a NullPointerException if I call items(null) but work fine if I just say items(). In order for this to work right, I have to change the line to be new HashSet<>(items ?: []) which, again, seems to defeat the entire purpose of having default method argument values.
What am I missing here?
In Groovy, default parameters generates overloaded methods. Thus, this:
def items(Set<String> items = []) {
new HashSet<>(items)
}
Will generate these two methods (I used javap to get these values):
public java.lang.Object items(java.util.Set<java.lang.String>);
public java.lang.Object items();
So when you call items(null) you are, in fact, passing some value, and items(Set) method will be used.
You can also refer to this question about default parameters.

In which sequence does method call work in groovy?

I am using groovy 2.3.8
I am trying to figure out how method calls work in groovy. Specifically if we have a Java class hierarchy each having a metaClass like below
class A {
}
A.metaClass.hello = {
"hello superclass"
}
class B extends A {
}
B.metaClass.hello = {
"hello subclass"
}
If I use new B().hello() I get hello subclass. If I remove meta class of B then I get hello superclass.
Based on changing the above example I think groovy goes in the below sequence to find which method to call
method-in-subclass's-metaclass ?: subclass-metho ?: method-in-superclass's metaclass ?: method-in-superclass
So how does groovy lookup which method to call?
Well, the hierarchy is the expected object oriented programming method overloading, which is what you witnessed. What differs is the dispatching. Instead of starting with a method lookup in instance's class, it begins with the MOP (meta object protocol).
In layman's terms, because the MOP is programmable, so is the way methods are invoked :)
How it works
The following diagram from Groovy's documentation shows how methods are looked up.
What's not clear in the diagram is that there's an instance metaclass as well, and it comes before the class's metaclass.
Something that may help is looking at an object's or class's .metaClass.methods Methods added through inheritance, traits, metaclass, etc are listed in a flat list. The inheritance hierarchy is flattened. .metaClass.metaMethods on the other hand seems to contain methods added via the GDK. From the list I could not tell method precedence :(
Based on observation, the rule seems to be this: the last MetaClass standing wins.
class A { }
class B extends A { }
A.metaClass.hello = {
"hello superclass"
}
B.metaClass.hello = {
"hello subclass"
}
def b = new B()
assert b.hello() == "hello subclass"
b.metaClass = A.metaClass
assert b.hello() == "hello superclass"

How can I intercept execution of all the methods in a Java application using Groovy?

Is it possible to intercept all the methods called in a application? I'd like to do something with them, and then let them execute. I tried to override this behaviour in Object.metaClass.invokeMethod, but it doesn't seem to work.
Is this doable?
Have you looked at Groovy AOP? There's very little documentation, but it allows you to define pointcuts and advice in a conceptually similar way as for AspectJ. Have a look at the unit tests for some more examples
The example below will match all calls to all woven types and apply the advice before proceeding:
// aspect MyAspect
class MyAspect {
static aspect = {
//match all calls to all calls to all types in all packages
def pc = pcall("*.*.*")
//apply around advice to the matched calls
around(pc) { ctx ->
println ctx.args[0]
println ctx.args.length
return proceed(ctx.args)
}
}
}
// class T
class T {
def test() {
println "hello"
}
}
// Script starts here
weave MyAspect.class
new T().test()
unweave MyAspect.class
First of all, overriding Object.metaClass.invokeMethod doesn't work because when Groovy tries to resolve a method call for a type X, it checks the metaClass of X, but not the metaClass of its parent class(es). For example, the following code will print "method intValue intercepted"
Integer.metaClass.invokeMethod = {def name, def args ->
System.out.println("method $name intercepted")
}
6.intValue()
// Reset the metaClass
Integer.metaClass = null
But this code will not:
Object.metaClass.invokeMethod = {def name, def args ->
System.out.println("method $name intercepted")
}
6.intValue()
// Reset the metaClass
Object.metaClass = null
Your question was "Is it possible to intercept all the methods called in a application?", but could you be a bit more precise about whether you want to:
Intercept calls to Groovy methods, Java methods, or both
Intercept calls to only your Groovy/Java methods or also intercept calls to Groovy/Java library classes
For example, if you only want to intercept calls to your Groovy classes, you could change your classes to implement GroovyInterceptable. This ensures that invokeMethod() is invoked for every method called on those classes. If the nature of the interception (i.e. the stuff you want to do before/after invoking the called method) is the same for all classes, you could define invokeMethod() in a separate class and use #Mixin to apply it to all your classes.
Alternatively, if you also want to intercept calls to Java classes, you should check out the DelegatingMetaClass.

Resources