Trouble using ArgumentMatchers in Mockito using when() - java

I'm writing some unit test with Mockito and I have the following situation:
AmazonS3 mockedS3 = Mockito.mock( AmazonS3.class )
Bucket mockBucket = Mockito.mock( Bucket.class )
Mockito.when( mockBucket.getName() ).thenReturn("bucket-1-pub")
Mockito.when(mockedS3.doesBucketExistV2("bucket-1-pub")).thenReturn(false)
// here I'm setting up a mock that accepts any CreateBucketRequest
Mockito.when( mockedS3.createBucket(any(CreateBucketRequest.class)) )
.thenReturn( mockBucket )
// execute the code under test
String result = doSomething()
// this is the line of the error where it doesn't see a call to createBucket
// for any CreateBucketRequest
Mockito.verify( mockedS3 ).createBucket( any(CreateBucketRequest.class) )
Here is the error I get:
Wanted but not invoked:
amazonS3.createBucket(
<any com.amazonaws.services.s3.model.CreateBucketRequest>
);
-> at com.amazonaws.services.s3.AmazonS3$createBucket$3.call(Unknown Source)
However, there were exactly 2 interactions with this mock:
amazonS3.doesBucketExistV2("bucket-1-pub");
-> at com.fuseanalytics.archiver.model.dao.AmazonFileDao.checkBucket(AmazonFileDao.java:142)
amazonS3.createBucket(
com.amazonaws.services.s3.model.CreateBucketRequest#255e5e2e
);
-> at com.fuseanalytics.archiver.model.dao.AmazonFileDao.checkBucket(AmazonFileDao.java:147)
Wanted but not invoked:
amazonS3.createBucket(
<any com.amazonaws.services.s3.model.CreateBucketRequest>
);
-> at com.amazonaws.services.s3.AmazonS3$createBucket$3.call(Unknown Source)
However, there were exactly 2 interactions with this mock:
amazonS3.doesBucketExistV2("bucket-1-pub");
-> at com.fuseanalytics.archiver.model.dao.AmazonFileDao.checkBucket(AmazonFileDao.java:142)
amazonS3.createBucket(
com.amazonaws.services.s3.model.CreateBucketRequest#255e5e2e
);
-> at com.fuseanalytics.archiver.model.dao.AmazonFileDao.checkBucket(AmazonFileDao.java:147)
So from tracing out the call my amazonS3.createBucket() call is being called with a CreateBucketRequest, but instead of returning the mockBucket that I have configured. It just returns null, then when I verify it was called that call doesn't match the conditions of verify and blamo exception city.
Update: Things I've tried have been to move the when() calls so they align with the order in which the methods will be called in the code. Didn't work. (I glad that didn't work because how awful would that be?! So much for black box testing right?) I also tried to remove the verify() call for createBucket(). That just resulted in the next verify (not pictured) to blow up because createBucket() still didn't return what I configured.
I can't see how this isn't working so I need some help to see my mistake.

Ok so I left out an important detail my apologies to those who commented. I'm writing my test with Groovy. And it turns out it's Groovy's fault. I started to suspect that Groovy was adding it's Groovy methods to Objects and that might make them appear not the same to Mockito. So while it says it had an interaction with createBucket(CreateBucketRequest). It wasn't recognizing CreateBucketRequest and CreateBucketRequest + Groovy Default Methods as the same thing when using any() matcher.
Now why this is happening is for the Mockito devs to figure out. I suppose I should just go use Spock instead of junit, but that is for another day. Thanks for the help.

Related

Calling methods between groovy scripts with correct parameters

I just started learning about groovy and trying to transpose my java code to groovy scripts. Usually java allows you have a class with only methods that you can call from other classes. I wanted to translate that to groovy. I have in one file - lets call it File1- a method like this:
def retrieveData(String name){
// do something
}
and in the second file, File2, I call File1 like this:
def file1Class = this.class.classLoader.parseClass(new File("../File1.groovy"))
and then try to call the method in File1 like this:
def data = file1Class.retrieveData("String")
but it keeps giving me this error - MissingMethodException:
groovy.lang.MissingMethodException: No signature of method: static File1.retrieveData() is applicable for argument types: (java.lang.String) values: [String] Possible solutions: retrieveData(java.lang.String)
so it does recognize that I am sending in the correct number of parameters and even the correct object, but it isn't running the method as it should?
Is there something I am missing? I tried to remove the object definition from the method - in other words - like this:
def retrieveData(name){
// do something
}
but that didn't work either. I am clueless about what the next step would be. Can anyone please help push me in the right direction? I would greatly appreciate it.
See the answer provided in this StackOverflow reponse.
Use the GroovyScriptEngine class. What does the GroovyScriptEngine do? From the docs:
Specific script engine able to reload modified scripts as well as
dealing properly with dependent scripts.
See the example below.
def script = new GroovyScriptEngine( '.' ).with {
loadScriptByName( '..\File1.groovy' )
}
this.metaClass.mixin script
retrieveData()
Note how we use the loadScriptByNamemethod to
Get the class of the scriptName in question, so that you can
instantiate Groovy objects with caching and reloading.
This will allow you to access Groovy objects from files however you please.

How to mock the second object in the same method?

Now I have a method to test using Mockito . However the method is kind of complicated. In the same method ,I need to new two objects both are the same type.
Timestamp beginTimestamp = new Timestamp(Long.parseLong(beginTimeLong));
Timestamp endTimestamp = new Timestamp(System.currentTimeMillis());
I want to mock the second object , endTimestamp , to throw an Exception , but I can not avoid the influence of beginTimestamp. Now my question is how to mock the second object, endTimeStamp, only ,and make it to throw out an exception when I call endTimestamp's certain method ,such as:
endTimestamp.getTime()
I tried to write my test code which is shown below ,
#Ignore
public void getSynPotentialShopBeginTimeAndEndTest4() throws Exception {
Timestamp beginTimestamp = PowerMockito.mock(Timestamp.class);
Timestamp endTimestamp = PowerMockito.mock(Timestamp.class);
PowerMockito.whenNew(Timestamp.class).withAnyArguments().thenReturn(beginTimestamp).thenReturn(endTimestamp);
when(endTimestamp.getTime()).thenThrow(RuntimeException.class);
redisService.getSynPotentialShopBeginTimeAndEnd();
}
It doesn't work either. These code don't have any red wavy underline ,but when I tried to run it, I got an exception like this:
org.mockito.exceptions.base.MockitoException:
Incorrect use of API detected here:
You probably stored a reference to `OngoingStubbing` returned by `when()` and called stubbing methods like `thenReturn()` on this reference more than once.
Examples of correct usage:
when(mock.isOk()).thenReturn(true).thenReturn(false).thenThrow(exception);
when(mock.isOk()).thenReturn(true, false).thenThrow(exception);
Is there another solution I can solve the problem? Anyway , only if the problem to be solved ,that's OK.
Try this
PowerMockito.whenNew(Timestamp.class).withAnyArguments().thenReturn(beginTimestamp,endTimestamp);
Instead of PowerMockito.whenNew(Timestamp.class).withAnyArguments().thenReturn(beginTimestamp).thenReturn(endTimestamp);

Execute a Scala action inside an Java Controller (PlayFramework)

I've create an app using the Playfrawork with Java.
And I'm using the SecureSocial plugin on it.
Inside my controller there is a method that one of the process of it is to execute the handle start reset password inside the SecureSocial.
But that method is written in Scala.
If I refer the method inside my Java source like this:
Registration.handleStartResetPassword();
Nothing happens! Same if I change to the following line:
Registration.handleStartResetPassword().apply();
Same as the following source code block:
play.api.libs.iteratee.Iteratee<byte[], SimpleResult> it = Registration.handleStartResetPassword().apply(ctx()._requestHeader());
Future<SimpleResult> future = it.run();
Option<Try<SimpleResult>> result = future.value();
SimpleResult res = result.get().get();
I removed all my code and just tried to execute the Secure Social code but nothing happens.
Here is my method:
public static Result resetPassword() {
Registration.handleStartResetPassword().apply();
return TODO;
}
My route is this one:
POST /reset controllers.ProfileController.resetPassword
Edited: Added another way that I've tried to run but just didm't got the method running.
When you call handleStartResetPassword() you get an instance of Action back, it doesn't actually do anything until you to feed it with a particular request by calling Action.apply(request) which will then actually run the logic for that controller action and return a Future<Result>.
Not entirely sure if you can bridge backwards and get a play Java async result out of that though.

Configure mockito to print actual argument values in verification error messages

When describing failed verification, by default Mockito prints only call sites where interactions happened. Like this:
Wanted but not invoked:
proxyListener.foundTemplateParam(
"fooBar2",
isNull(),
isNull()
);
-> at foo.ProxyHandlerTest.testThatImplicitParamsScannedCorrectly(ProxyHandlerTest.java:136)
However, there were other interactions with this mock:
-> at foo.ProxyHandler.<init>(ProxyHandler.java:99)
-> at foo.ProxyHandler.<init> (ProxyHandler.java:100)
-> at foo.ProxyHandler.scanForParamSetters(ProxyHandler.java:222)
-> at foo.ProxyHandler.<init>(ProxyHandler.java:102)
-> at foo.ProxyHandler.<init>(ProxyHandler.java:104)
That's useful information but I would also like to see what arguments where passed during those interactions. Is there a way to achieve this?
P. S. I know about mocking with withSettings().verboseLogging(). But it's too verbose and is printed to stdout instead of adding this info to assertion error message.
Update:
Mockito 1.9.0 doesn't support customization of exception error messages out of the box (I just checked their sources).
the safest place to do that is an answer that prints arguments and return the given value.
You could then write something like :
given(some.callWith(arg1, arg2)).will(printArgsAndReturn("some value"));
where printArgsAndReturn("some value") actually returns your custom answer.

Stackoverflow calling metaClass method on Map

This piece of code is causing a stackOverflow exception:
ISerializer serializer = buildSerializer(TestDataProvider.getAuthor());
ASObject result = (ASObject) serializer.serialize();
assert result.isNotLazyProxy
The StackOverflow is being thrown on this line: assert result.isNotLazyProxy. Note, the isNotLazyProxy method never actually gets called.
isNotLazyProxy is a extension method (what are these called in groovy?) defined as follows:
/**
* Asserts that this ASObject is not a lazy loaded proxy,
* ie - that all of it's properties' values have been included
*/
ASObject.metaClass.isNotLazyProxy = { ->
assert delegate[HibernateProxyConstants.PROXYINITIALIZED] == true
return true;
}
However, setting a breakpoint on the first line of that closure shows that it never gets called.
Instead, there's a StackOverflow thrown:
java.lang.StackOverflowError
at java.lang.System.arraycopy(Native Method)
at java.lang.String.getChars(String.java:855)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:391)
at java.lang.StringBuffer.append(StringBuffer.java:224)
at java.lang.StringBuffer.<init>(StringBuffer.java:104)
at org.codehaus.groovy.runtime.InvokerHelper.formatMap(InvokerHelper.java:557)
at org.codehaus.groovy.runtime.InvokerHelper.format(InvokerHelper.java:530)
at org.codehaus.groovy.runtime.InvokerHelper.formatList(InvokerHelper.java:602)
at org.codehaus.groovy.runtime.InvokerHelper.format(InvokerHelper.java:527)
at org.codehaus.groovy.runtime.InvokerHelper.formatMap(InvokerHelper.java:575)
snip
I'm not sure if it's relevant, but ASObject is a subclass of a Map, and it's contents may have properties that refer to other keys within itself.
I would've have thought it was relevant, except the StackOverflow appears to indicate that groovy is traversing the members of the map.
What's going on? Why is this stackoverflow occurring?
assert result.isNotLazyProxy is probably not doing what you want to do.
In groovy map.somehing is translated to map.get(something). See http://groovy.codehaus.org/JN1035-Maps :
assert map2.class == null
//field syntax always refers to value of key, even if it doesn't exist
//use getClass() instead of class for maps...
assert map2.getClass() == LinkedHashMap //the kind of Map being used
So use assert result.isNotLazyProxy().
Of course result.isNotLazyProxy should return null in your case, and the assert result.isNotLazyProxy assertion should fail. When this assertion fails groovy will display an assertion error, and the map. In your case formatting the map fails for some reason.
Reason it fails:
It is a known bug, see example. As I see, it has nothing to do with ASObject, as it uses no lists.
At first glance, it looks like something else is causing the endless recursion...
Does ASObject have any other metaClass methods? Especially those overriding the getAt( key ) method of Map
I came up with this quick test script, and it seems to work fine as I'd expect (and I think it does the same as what you say you're doing)
class ASObject {
#Delegate Map map = [ 'PROXYINITIALIZED' : true ]
}
ASObject.metaClass.isNotLazyProxy = { ->
assert delegate[ 'PROXYINITIALIZED' ] == true
return true
}
assert new ASObject().isNotLazyProxy()

Categories