I'm not having any luck getting Mockito to capture function argument values! I am mocking a search engine index and instead of building an index, I'm just using a hash.
// Fake index for solr
Hashmap<Integer,Document> fakeIndex;
// Add a document 666 to the fakeIndex
SolrIndexReader reader = Mockito.mock(SolrIndexReader.class);
// Give the reader access to the fake index
Mockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))
I can't use arbitrary arguments because I'm testing the results of queries (ie which documents they return). Likewise, I don't want to specify a specific value for and have a line for each document!
Mockito.when(reader.document(0)).thenReturn(document(fakeIndex(0))
Mockito.when(reader.document(1)).thenReturn(document(fakeIndex(1))
....
Mockito.when(reader.document(n)).thenReturn(document(fakeIndex(n))
I looked at the callbacks section on the Using Mockito page. Unfortunately, it isn't Java and I couldn't get my own interpretation of that to work in Java.
EDIT (for clarification):
How do I get get Mockito to capture an argument X and pass it into my function? I want the exact value (or ref) of X passed to the function.
I do not want to enumerate all cases, and arbitrary argument won't work because I'm testing for different results for different queries.
The Mockito page says
val mockedList = mock[List[String]]
mockedList.get(anyInt) answers { i => "The parameter is " + i.toString }
That's not java, and I don't know how to translate into java or pass whatever happened into a function.
I've never used Mockito, but want to learn, so here goes. If someone less clueless than me answers, try their answer first!
Mockito.when(reader.document(anyInt())).thenAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Object mock = invocation.getMock();
return document(fakeIndex((int)(Integer)args[0]));
}
});
Check out ArgumentCaptors:
https://site.mockito.org/javadoc/current/org/mockito/ArgumentCaptor.html
ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
Mockito.when(reader.document(argument.capture())).thenAnswer(
new Answer() {
Object answer(InvocationOnMock invocation) {
return document(argument.getValue());
}
});
You might want to use verify() in combination with the ArgumentCaptor to assure execution in the test and the ArgumentCaptor to evaluate the arguments:
ArgumentCaptor<Document> argument = ArgumentCaptor.forClass(Document.class);
verify(reader).document(argument.capture());
assertEquals(*expected value here*, argument.getValue());
The argument's value is obviously accessible via the argument.getValue() for further manipulation / checking or whatever you wish to do.
With Java 8, this could be something like this:
Mockito.when(reader.document(anyInt())).thenAnswer(
(InvocationOnMock invocation) -> document(invocation.getArguments()[0]));
I am assuming that document is a map.
Related
I notice this problem during the following test:
verify(mockedObject).functionCall(argThat(inputStream -> {
final String content = ... // read the inputStream
assertEquals(expectedContent, content);
return true;
}));
It will actually fail although the assertEquals assertion is true. I debug the test, find that the lambda function is reached twice, and at the second time, the cursor of the stream is at the end of the stream. That's why it fails.
So I have to reset the stream first:
verify(mockedObject).functionCall(argThat(inputStream -> {
inputStream.reset();
final String content = ... // read the inputStream
assertEquals(expectedContent, content);
return true;
}));
The question is, why the lambda is triggered twice? Is this by design? Does it have a document?
Mockito version: 2.22
Junit version: 5.6.0
Java version: 1.8
Update
The method is called exactly once, and the inputs of two lambda calls are exactly the same input. Actually, they are the same object. The only thing I have to do is to reset the stream, as it has been exhausted by the first lambda call.
I wouldn't say it's "by design", rather that it's what the current implementation does. The Mockito Times class which performs your assertions has the following method (I'm on a pretty recent version so YMMV):
public void verify(VerificationData data) {
List<Invocation> invocations = data.getAllInvocations();
MatchableInvocation wanted = data.getTarget();
if (wantedCount > 0) {
checkMissingInvocation(data.getAllInvocations(), data.getTarget());
}
checkNumberOfInvocations(invocations, wanted, wantedCount);
}
Both checkMissingInvocation and checkNumberOfInvocations perform independent filtering on the list of all invocations to retain the relevant ones, so any matcher you declare ends up being executed twice for each invocation. It's actually exactly the same call:
List<Invocation> actualInvocations = findInvocations(invocations, wanted);
Maybe the filtered list could be cached, but the point is that unless otherwise specified in the documentation, you cannot assume that the function you supply will be executed only once. Also, predicate functions are generally expected to be free of side-effects.
Until now my parser is able to parse functions with a known parameter number using expressions such as this
<FUNCTION><OPENPAR> son=expression() <COMMA> son1=expression() <CLOSEPAR>
Also, optional parameters can also easily be handled
<FUNCTION><OPENPAR> son=expression() <COMMA> son1=expression() [<COMMA> son2=expression()] <CLOSEPAR>
However, I haven't been able to find documentation regarding the possibility of capturing an unknown number of parameters. My guess is something like this
<FUNCTION><OPENPAR> son=expression() <COMMA> son1=expression() [<COMMA> son2=expression()]+ <CLOSEPAR>
But in this case I don't know how to capture of these multiple parameters should be done.
Any ideas or examples? (or if anyone knows that this is impossible)
Let's say at least one parameter is required. Then, you would need something like:
private X myFunction():
{
X result = new X();
}
{
<FUNCTION>
<OPENPAR>
son=expression() { result.params.add(son); }
( <COMMA> son=expression() { result.params.add(son); } )*
<CLOSEPAR>
{ return result; }
}
To sum up, my approach is to:
Create result Java class X and use it as you would in plain Java.
Initialize what's required at the beginning.
Return filled object.
If you still need working example, you may find this useful.
In a PreProcessor I am writing I can successfully update GET query string via sampler.
However if I use the same approach with POST, while I can list the FORM fields via getArguments(), the value does not get set.
Arguments arguments = sampler.getArguments();
for (int i=0; i<arguments.getArgumentCount(); i++) {
Argument argument = arguments.getArgument(i);
if (argument.getName().equals("page_submission_id")) {
String newVal = "8743718386872";
argument.setValue(newVal);
System.out.println("Setting arg["+argument.getName()+"] to["+newVal+"]");
}
}
sampler.setArguments(arguments);
printArgs(arguments);
The output from this shows Arguments values are unchanged.
Setting arg[page_submission_id] to[8743718386872]
Arguments After
...
Found arg[page_submission_id] is[XXXXXXXXXXXXX]
...
Having dug into the jmeter code a bit further, there is a "runningVersion" attribute of an Attribute object which (via isRunningVersion()) is set true.
I have tried a few ways to get round this:
force runningVersion to false - then values are set but a GET message is sent
create a new Arguments object and add new Argument entries to it with values - this does not change the values
Can anyone point out the official way to set POST FORM field values before they get sent?
Thanks
Well, you assigning a new value to an argument, but I fail to see where you updating sampler's arguments with the argument having the new value.
I'm a strong believer of KISS principle so instead of adding some more lines I would recommend simplifying your script as follows:
import org.apache.jmeter.config.Argument;
sampler.getArguments().removeArgument("page_submission_id");
sampler.addArgument("page_submission_id","8743718386872");
Also I hope you're using JSR223 PreProcessor and Groovy language.
I managed to resolve this:
(initially) by cleaning up the Thread Pool, as my initial
attempts had included a number of things like "Regular Expression
Extractors" and "User defined variables". Once those were removed
the approach I was using successfully changed the argument values, and
(when deeper in to my setup the problem came back) by adding the creation of a new Argments object and inserting (in the same order) new Argument objects with the value set as I require. Then setting the sampler to use that new Arguments object.
Arguments newArgs = new Arguments();
Arguments arguments = sampler.getArguments();
for (int i=0; i<arguments.getArgumentCount(); i++) {
Argument argument = arguments.getArgument(i);
HTTPArgument newArg = new HTTPArgument();
newArg.setName(arguments.getName());
if (arguments.getName().equals("field_to_replace")) {
newArg.setValue("new value");
}
else {
newArg.setValue(arguments.getValue());
}
newArgs.addArgument(newArg);
}
sampler.setArguments(newArgs);
My take is that this down to the "if (isRunningVersion())" test within setProperty() used by "Argument.setValue()" which I'm tripping over.
While this appears to work (for my test cases so far) I appreciate that overriding this may not be the correct formal approach.
Apologies if this is a bit of a weird one...
I have a program written in Java which utilises the ScriptEngine to process user provided JavaScript to extend my application. However, this specific question is related to general JavaScript as opposed to Java or it's ScriptEngine, but I am just explaining this to set the context.
I have a function which returns a string when called - let's call it a() as defined below:
var a = function() {
return "this is a";
};
When the user calls this function using a() it works fine and outputs "this is a". However, if the user forgets to include the parenthesis then it outputs my actual function definition - expecting this as I am no longer calling the function.
To catch this I have redefined the toString method of my Object to the following:
a.toString = function() {
return a();
};
This works fine when I use a in a string context as it calls the toString method implicitly, but if I attempt to pass it to a function then it doesn't call toString and I am left with a sun.org.mozilla.javascript.internal.InterpretedFunction.
I have looked at the other Function.prototype methods (i.e. apply, bind, constructor, etc) to try and override the method which is called as the function is passed to another function but none of them fitted the bill. I am basically looking for a way of converting a Function to a string type object whenever it is used without the parenthesis - i.e a === a(). For people who might ask why don't I define a as a string to start with, my function returns a string constructed from other information the user has provided.
Maybe the solution is to make my users write syntactically correct JavaScript, but my users are far from programmers. I could also add some form of pre-parsing which checks for missing parenthesis and adds them in dynamically before I execute it using the ScriptEngine. However, although both of these options will work, I am looking for an easier way.
Neither a.toString nor a.prototype.toString will allow you to forget the parenthesis. .toString allow you to do:
var a = function() {
return "this is a";
};
a.prototype.toString = function () {
return "something";
};
var A = new a;
alert(A + ''); // something
A.toString = function () {
return "something else";
};
alert(A + ''); // something else
You shouldn't want in your code both a() and a return the same thing, this looks like a very bad idea.
An option to get myObject.myVar return a custom dynamic string is defineGetter https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Object/defineGetter
I'm having a problem with ArgumentCaptor not being able to record the
arguments when calling the same method a number of times.
Basically this does not seem to work:
List<Dummy> mList = mock(List.class);
Dummy dummy = new Dummy();
when(mList.get(anyInt())).thenReturn(dummy);
Dummy d = mList.get(12);
d.setName("John");
mList.add(d);
Dummy g = mList.get(10);
g.setName("Ben");
mList.add(g);
...
verify(mymock, times(3)).doStuff(captor.capture));
assertEquals("John", captor.getAllValues().get(0).getName());
assertEquals("Ben", captor.getAllValues().get(1).getName());
assertEquals("Don", captor.getAllValues().get(2).getName());
The value of getName() is always set to "Don".
I have also tried using InOrder, with the same outcome.
Feature (and me stupiud) or bug?
To better explain the issue I have created a use case:
http://pastebin.com/RE1UzJ4F
Cheers
iwein is correct; however, there are some situations (such as embedded systems) in which memory is scarce and you do not want to use or cannot use immutability.
A workaround I have found is to use a different mock for each invocation, then verify a list of mocks that each have one invocation.
List<Mock> mocks = new ArrayList<Mock>();
...init list w/ mocks using for loop...
List<Object[]> expectedArgs = new ArrayList<Object[]>();
..init list w/ desired args...
mocks.get(0).callMethod(1, 2);
...do that some more...
for(int i = 0; i < mocks.size(); i++) {
Object[] desiredArgs = expectedArgs.get(i);
verify(mocks.get(i)).callMethod((int) desiredArgs[0], (int) desiredArgs[1]);
}
It is not as pretty, but you do not have to make your classes immutable this way.
The java doc for ArgumentCaptor suggests what you are trying, so I'd say this is a bug. However, it is a bug in your code.
The problem is that you're changing the name of the same dummy each time you're invoking setName(..). I'd suggest that you make Dummy immutable and avoid setters wherever you can. That will avoid these types of bugs.
If you cannot make your Dummy immutable to force the issue you should at least pass a different instance from each get. Doing
when(mList.get(anyInt())).thenReturn(new Dummy(), new Dummy(), new Dummy());
Would fix the problem.
I had this problem and ended up using atLeastOnce, like so:
private ActionRequest getRequestedAction() {
ArgumentCaptor<ActionRequest> captor = ArgumentCaptor.forClass(ActionRequest.class);
verify(adapter, atLeastOnce()).requestAction(captor.capture());
return captor.getValue();
}