Mockito Mock a method call called twice - java

I am trying to use mockito to mock a method. However the class I am injecting mocks with calls the method twice while sending in two different objects of the same type, but depending the values in the object determine the output of the method.
So, for example, If I am trying to mock
public ArrayList<example> attemptToMock(testObject testing)
Lets sat type testObject has a string value in it.
So if the string value in testObject is "OK" then attemptToMock should output an array of two objects in it. If testObject string value is "NO" then the Array list sent out only has one Object.
How to I write a test to handle a call so that a class can call attemptToMock twice, within the same method, and I can mock out its output it so depending on the values within testObject. I can mock it to send out different arrays.

A few options:
Override equals and hashCode on your object (TestObject). This is only feasible if all of the values on your object are predictable, and may be more work than other solutions, but if you need to write equals and hashCode anyway (for Map and Set behavior, for example) this is a reasonable solution.
// Mockito compares with objects' equals(Object) methods by default.
when(collaborator.attemptToMock(object1)).thenReturn(array1);
when(collaborator.attemptToMock(object2)).thenReturn(array2);
Write a Hamcrest matcher and use that to match the arrays. This acts as a compact analogue to equals for a specific case, and is especially handy if you need to change behavior based on the same value in many tests.
public class IsATestObjectWithValue extends TypeSafeMatcher<TestObject> {
private final String expectedValue;
public IsATestObjectWithValue(String expectedValue) {
super(TestObject.class);
this.expectedValue = expectedValue;
}
#Override public void matchesSafely(TestObject object) {
// object will never be null, but object.value might.
return expectedValue.equals(object.value);
}
}
Now you can write an equivalent match as above:
when(collaborator.attemptToMock(argThat(new IsATestObjectWithValue("OK")))
.thenReturn(array1);
when(collaborator.attemptToMock(argThat(new IsATestObjectWithValue("NO")))
.thenReturn(array2);
Use an Answer, as wdf described. Anonymous inner Answers are common and pretty concise, and you get access to all of the arguments. This is especially good for one-off solutions, or if you want to explicitly and immediately fail the test if an invalid value (testObject.value) is passed in.
As a last resort, if the order of the calls is predictable, you can return multiple values in sequence.
when(collaborator.attemptToMock(any(TestObject.class)))
.thenReturn(array1).thenReturn(array2);
when(collaborator.attemptToMock(any(TestObject.class)))
.thenReturn(array1, array2); // equivalent
Either of the above lines will return array1 for the first call and array2 for the second call and all calls after it, regardless of the parameter. This solution will be much more brittle than your original question asks for--it'll fail if the call order changes, or if either of the calls is edited out or repeated--but is sometimes the most compact solution if the test is very temporary or if the order is absolutely fixed.

You can access the parameters passed into a mocked method invocation and vary the return value accordingly by using the Answer interface. See the answer to this question, and the docs for Answer.
Basically, the only weird/non-obvious thing going on here is that you have to downcast the parameters to the type you are expecting. So, in your case, if you are mocking a method that takes a single 'TestObject' parameter, then you'll have to do something like this inside of your 'answer' implementation:
Object[] args = invocation.getArguments();
TestObject testObj = (TestObject) args[0];
if ("OK".equals(testObj.value)) {
return new ArrayList(value1, value2);
} else if ("NO".equals(testObj.value)) {
return new ArrayList(singleObject);
}

Related

Method Reference of Java

According to Oracle Documentation, the String::compareToIgnoreCase is also a valid method reference, my question is that compareToIgnoreCase is not a static method, in other words, compareToIgnoreCase must be attached to a specific String instance. So how does JDK know which instance of String I refer when I use String::compareToIgnoreCase ?
Consider the following example using toUpperCase which is also an instance method.
It works in this case because the Stream item that is being handled is of the same type as the class of the method being invoked. So the item actually invokes the method directly.
So for
Stream.of("abcde").map(String::toUpperCase).forEach(System.out::println);
the String::toUpperCase call will be the same as "abcde".toUpperCase()
If you did something like this:
Stream.of("abcde").map(OtherClass::toUpperCase).forEach(System.out::println);
"abcde" is not a type of OtherClass so the OtherClass would need to look like the following for the stream to work.
class OtherClass {
public static String toUpperCase(String s) {
return s.toUpperCase();
}
}
String::compareToIgnoreCase is not used such as str1.compareToIgnoreCase(str2) would be.
It actually is used as a comparator.
E.g. you could compare it to
Arrays.sort(someIntegerArray, Collections.reverseOrder())
but in this case it would be
Arrays.sort(someStringArray, String::compareToIgnoreCase)
It is like there is an additional parameter, the actual instance, involved.
Example for String::compareToIgnoreCase:
ToIntBiFunction<String, String> func = String::compareToIgnoreCase;
int result = func.applyAsInt("ab", "cd"); // some negative number expected
We get a ToIntBiFunction - a two parameter function returning int - since the result is an int, the first parameter correspond to this of compareToIgnoreCase and the second function parameter is the parameter passed to compareToIgnoreCase.
maybe a bit easier:
ToIntFunction<String> f = String::length; // function accepting String, returning int
int length = f.applyAsInt("abc"); // 3
length does not accept any parameter, but the first argument of the function is used as the instance length is called on
The examples above are very abstract, just to show the types involved. The functions are mostly used directly in some method call, no need to use an intermediate variable

How do I get Mockito to mock a constant from another file?

EDIT: The method I'm testing calls this constant that's defined in another class, so I want to test that th emethod works independently of how the other class defines the constant. Mocking it was the first thing I could think of, but I'm open to other ideas for how to test it in a clean, secure way
(Class, method, and variable names are genericized)
I'm trying to figure out how to write a test.
One of my methods gets a constant from another class, like so:
OtherClass.CONSTANT
and this constant is defined as:
public static final List<Long> CONSTANT =
ImmutableList.of(1, 2);
In the test for this method, I want to mock this call. I've tried
when(OtherClass.CONSTANT).thenReturn(ImmutableList.of(1, 2));
but that gives me this error:
RegularImmutableList cannot be returned by otherFunction()
otherFunction() should return String
otherFunction() being some other function in the code base that doesn't seem to be related to anything I've been working on.
I've also tried
doReturn(ImmutableList.of(1, 2)).when(OtherClass.CONSTANT);
but, as you might be guessing, it gives me this error:
Argument passed to when() is not a mock!
Example of correct stubbing:
doThrow(new RuntimeException()).when(mock).someMethod();
I'm pretty lost as to how exactly I should be mocking this constant.
As you've discovered, you can't mock the value of a constant.
Likely the easiest method would be to convert your design to use an interface to supply the value, rather than using the value directly.
Something like:
interface ConstantSupplier {
List<Long> get();
}
public MyClass(ConstantSupplier supplier) {
this.supplier = supplier;
}
Then you would replace references to the constant to supplier.get().
This is now easy to mock:
ConstantSupplier supplier = mock(ConstantSupplier.class);
when(supplier.get()).thenReturn(List.of(4L, 9L));
Your non-mocked code could use a lambda to supply the real value:
obj = new MyClass(() -> OtherClass.CONSTANT);

What's the difference between Mockito Matchers isA, any, eq, and same?

I am confused on what's the difference between them, and which one to choose in which case. Some difference might be obvious, like any and eq, but I'm including them all just to be sure.
I wonder about their differences because I came across this problem:
I have this POST method in a Controller class
public Response doSomething(#ResponseBody Request request) {
return someService.doSomething(request);
}
And would like to perform a unit test on that controller.
I have two versions. The first one is the simple one, like this
#Test
public void testDoSomething() {
//initialize ObjectMapper mapper
//initialize Request req and Response res
when(someServiceMock.doSomething(req)).thenReturn(res);
Response actualRes = someController.doSomething(req);
assertThat(actualRes, is(res));
}
But I wanted to use a MockMvc approach, like this one
#Test
public void testDoSomething() {
//initialize ObjectMapper mapper
//initialize Request req and Response res
when(someServiceMock.doSomething(any(Request.class))).thenReturn(res);
mockMvc.perform(post("/do/something")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(req))
)
.andExpect(status().isOk())
.andExpect(jsonPath("$message", is("done")));
}
Both work well. But I wanted my someServiceMock.doSomething() in the MockMvc approach to receive req, or at least an object that has the same variable values as req (not just any Request class), and return res, just like the first. I know that it's impossible using the MockMvc approach (or is it?), because the object passed in the actual call is always different from the object passed in the mock. Is there anyway I can achieve that? Or does it even make sense to do that? Or should I be satisfied using any(Request.class)? I've tried eq, same, but all of them fail.
any() checks absolutely nothing. Since Mockito 2.0, any(T.class) shares isA semantics to mean "any T" or properly "any instance of type T".
This is a change compared to Mockito 1.x, where any(T.class) checked absolutely nothing but saved a cast prior to Java 8: "Any kind object, not necessary of the given class. The class argument is provided only to avoid casting."
isA(T.class) checks that the argument instanceof T, implying it is non-null.
same(obj) checks that the argument refers to the same instance as obj, such that arg == obj is true.
eq(obj) checks that the argument equals obj according to its equals method. This is also the behavior if you pass in real values without using matchers.
Note that unless equals is overridden, you'll see the default Object.equals implementation, which would have the same behavior as same(obj).
If you need more exact customization, you can use an adapter for your own predicate:
For Mockito 1.x, use argThat with a custom Hamcrest Matcher<T> that selects exactly the objects you need.
For Mockito 2.0 and beyond, use Matchers.argThat with a custom org.mockito.ArgumentMatcher<T>, or MockitoHamcrest.argThat with a custom Hamcrest Matcher<T>.
You may also use refEq, which uses reflection to confirm object equality; Hamcrest has a similar implementation with SamePropertyValuesAs for public bean-style properties. Note that on GitHub issue #1800 proposes deprecating and removing refEq, and as in that issue you might prefer eq to better give your classes better encapsulation over their sense of equality.
If your Request.class implements equals, then you can use eq():
Bar bar = getBar();
when(fooService.fooFxn(eq(bar)).then...
The above when would activate on
fooService.fooFxn(otherBar);
if
otherBar.equals(bar);
Alternatively, if you want to the mock to work for some other subset of input (for instance, all Bars with Bar.getBarLength()>10), you could create a Matcher. I don't see this pattern too often, so usually I create the Matcher as a private class:
private static class BarMatcher extends BaseMatcher<Bar>{
...//constructors, descriptions, etc.
public boolean matches(Object otherBar){
//Checks, casts, etc.
return otherBar.getBarLength()>10;
}
}
You would then use this matcher as follows:
when(fooService.fooFxn(argThat(new BarMatcher())).then...
Hope that helps!

is it possible to get the class of the interface <Set>

Am having some arguments say (String a, Treeset b, Set c)
and I try to get the class by arguments[i].getClass(); of the above arguments..
is Iit possible to get the class of the interface <Set>.
For example:
Class[] argumentTypes = new Class [arguments.length];
for (int i = 0 ; i < arguments.length ; i++)
{
argumentTypes[i] = arguments[i].getClass();
}
The code you've given will find the classes of the arguments (i.e. the values provided to the method) - but those can never be interfaces; they'll always be concrete implementations. (You can never pass "just a set" - always a reference to an object which is an instance of an implementation of the interface, or a null reference.)
It sounds like you want the types of the parameters - which you'd get via reflection if you absolutely had to, finding the Method and then getting the parameters from that with getParameterTypes. But given that you're within the method, you already know the parameter types, because they're at the top of the method... I'm not sure the best way of finding "the currently executing" method, if that's what you're after.
If you're just trying to get the class associated with Set, you can use Set.class of course. But again, it's not really clear what you're trying to do.
EDIT: Okay, judging from your comment, there are some logical problems with what you're trying to do. Going from the values of arguments to which method would be invoked is impossible in the general case, because you've lost information. Consider this, for example:
void foo(String x) {}
void foo(Object y) {}
foo("hello"); // Calls first method
foo((Object) "hello"); // Calls second method
Here the argument values are the same - but the expressions have a different type.
You can find all methods which would be valid for the argument values - modulo generic information lost by type erasure - using Class.isAssignableFrom. Does that help you enough?
Note that you'll also need to think carefully about how you handle null argument values, which would obviously be valid for any reference type parameter...
You can use http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getInterfaces()
You will get the class what the caller provided.
I mean,in below class you will get HashSet.
Set set=new HashSet();
System.out.println(set.getClass());
You can do this in two ways given below
Set s = new //any class that implements it for example HashSet or TreeSet etc.;
s.getClass().getName(); //This will return the name of the subclass which is refered by s.
or if in other way can do it
Set s = null;
s.getClass();//This causes NullPointer Exception

Unit Test - Check a method call with an object that doesn't override equals

This is a general question on how to unit-test a Java Class using mock objects.
I can summarize my problem with this example. Let's say I've an Interface called MyInterface.java and a "TwoString" Object that doesn't override equals()
"TwoString.java"
private String string1;
private String string2;
public TwoString(String string1, String string2) {
this.string1 = string1;
this.string2 = string2;
}
...getters..setters..
"MyInterface.java"
void callMe(TwoString twoString);
Then I have "MyClass.java" Object. Its constructor accepts a concrete implementation of MyInterface.
MyClass methodToTest() contains the logic to create a TwoString oject in some way. Let's say that it will be created as
new TwoString("a","b")
So when methodToTest() is called it creates this TwoString object that will be passed to the Interface method callMe(TwoString twoString).
I basically want to mock the Interface. Create a MyClass object with this mock. Then verify that the mock method is called with a specific instance of TwoString.
I'm using EasyMock and this is some java code
"MyClassTest.java"
public void test() throws Exception {
MyInterface myInterfaceMock = createMock(MyInterface.class);
MyClass myClass = new MyClass(myInterfaceMock);
myInterfaceMock.callMe(new TwoString("a","b")); <--- fails here
expectLastCall();
replay(myInterfaceMock);
myClass.methodToTest();
verify(myInterfaceMock);
Here comes the problem. The TwoString object that I'm expecting in the call
myInterfaceMock.callMe(new TwoString("a","b"));
is different from the one generated in MyClass.methodToTest() because TwoString.java doesn't override equals.
I can skip the problem on the TwoString instance using
myInterfaceMock.callMe((TwoString)anyObject());
but I want to be sure that the interface method is called with a specific instance of TwoString that contains "a" as string1 and "b" as string2.
In this case the TwoString object is very simple and it will be easy to override the equals method - but what if I need to check a more complex object.
Thanks
edit:
I'll try to make it more readable with this example
public class MyClassTest {
private MyClass myClass;
private TaskExecutor taskExecutorMock;
#Before
public void setUp() throws Exception {
taskExecutorMock = createMock(TaskExecutor.class);
myClass = new MyClass(taskExecutorMock);
}
#Test
public void testRun() throws Exception {
List<MyObj> myObjList = new ArrayList<MyObj>();
myObjList.add(new MyObj("abc", referenceToSomethingElse));
taskExecutorMock.execute(new SomeTask(referenceToSomethingElse, ???new SomeObj("abc", referenceToSomethingElse, "whatever"))); <--- ??? = object created using data in myObjList
expectLastCall();
replay(taskExecutorMock);
myClass.run(myObjList);
verify(taskExecutorMock);
}
}
???SomeObj = object created by myClass.run() using data contained in myObjList.
Let's say that SomeObj comes from a third party library and it doesn't override equals.
I want to be sure that the taskExecutorMock.execute() method is getting called with a specific instance of that SomeObj
How can I test that the myClass.run() is actually calling the taskExecutorMock method with a correct instance
It is possible to use a custom equals matching method using org.easymock.IArgumentMatcher.
It should look something like:
private static <T extends TwoString> T eqTwoString(final TwoString twoString) {
reportMatcher(new IArgumentMatcher() {
/** Required to get nice output */
public void appendTo(StringBuffer buffer) {
buffer.append("eqTwoString(" + twoString.getString1() + "," + twoString.getString2() + ")");
}
/** Implement equals basically */
public boolean matches(Object object) {
if (object instanceof TwoString) {
TwoString other = (TwoString) object;
// Consider adding null checks below
return twoString.getString1().equals(object.getString1()) && twoString.getString2().equals(object.getString2());
}
else {
return false;
}
}
});
return null;
}
And is used as follows:
myInterfaceMock.callMe(eqTwoString(new TwoString("a","b")));
Some details may not be correct, but in essence it's how I've done it before. There is another example and more thorough explanations available in the EasyMock documentation. Just search for IArgumentMatcher.
First up - you probably mean "override equals" rather than implement, since all classes have some implementation of equals (the one they inherit from Object if they don't override anything else).
The answer in this case is simple - all value objects really really ought to implements equals and hashcode. Whether it's a simple one like TwoString, or the more complex object you allude to, it should be the object's responsibility to check whether it is equal to some other object.
The only other alternative would be to basically deconstruct the object in your test code - so instead of
assertEquals(expected, twoStr);
you'd do
assertEquals(expected.getStringOne(), twoStr.getStringOne());
assertEquals(expected.getStringTwo(), twoStr.getStringTwo());
Hopefully you can see that this is bad in at least three ways. Firstly, you're basically duplicating the logic that should be in the class' own equals() method; and anywhere that you want to compare these objects you'll have to write the same code.
Secondly, you can only see the object's public state, there could well be some private state that causes two apparently similar objects to be not equal (e.g. a Lift class could have a publically accessible "floor" attribute, but private "going up or down" state too).
Finally, it's a violation of the Law of Demeter for a third-party class to be basically messing about with the internals of TwoString trying to work out whether the things are equal.
The object itself should implement its own equals() method - pure and simple.
Take a look at Jakarta Commons Lang: EqualsBuilder.reflectionEquals()
While I agree with dtsazza that all value objects should have an equals() (and hashCode()) method, they're not always appropriate to testing: most value objects will base equality on a key, rather than on all fields.
At the same time, I'm leery of any test that wants to check all fields: it seems to me to be saying "make sure this method didn't change something that I wasn't planning for it to change." Which is a valid test, and on some level a very well-meaning test, but it's a little scary that you feel the need for it.
In this case the TwoString object is very simple and it will be easy to override the equals method - but what if I need to check a more complex object.
Once your objects start becoming so complex that you can't trivially check if they're equal from elsewhere, you should probably refactor and inject them as a dependency. This would change the design, but usually that's for the better.
You also seem to be relying on some knowledge of the internal behaviour of your classes. The above is an interaction test between two classes, which still sort of works, but the bigger your set of tested components gets, the less you can really still talk about "unit" tests. At a certain point you leave the realm of unit tests and you start doing integration tests, in which case you might be better off with a full blown test harness and isolating behaviour in certain places...
You can achieve this with argument captors in Mockito 1.8.
http://mockito.googlecode.com/svn/branches/1.8.0/javadoc/org/mockito/Mockito.html#15
I know you are using EasyMock but changing to Mockito is easy and it's much better!

Categories