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

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!

Related

Equivalent of Answers.RETURNS_DEEP_STUBS for a spy in mockito

I have been unable to find a way to use "Deep Stubs" for stubbing methods on a spy in Mockito. What I'm looking to do is something like this:
#Spy private Person person = //retrieve person
#Test
public void testStubbed() {
doReturn("Neil").when(person).getName().getFirstName();
assertEquals("Neil", person.getName().getFirstName());
}
The code above compiles with no issues, but upon running the test, it fails saying that the return type (the Name class, in this case) cannot be returned by getName().
Normally, when mocking, you have to use
#Mock(answer = Answers.RETURNS_DEEP_STUBS) for each mocked object. However, spy does not seem to have anything like this.
Has anyone ever successfully done deep stubbed mocking using a spy?
The error I'm receiving is listed below:
String cannot be returned by getName()
getName() should return Name
Due to the nature of the syntax above problem might occur because of:
1. Multithreaded testing
//I'm not doing multithreaded testing
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies with doReturn|Throw() family of methods
//As shown above, I'm already using the doReturn family of methods.
While I'd still like to know if there's a better way to do this, I'd like to post a solution for anyone who comes looking.
The solution below works fine, by requiring you to create a new mock (or even a real object/spy) for each level of your dependencies. In other words, instead of chaining your method calls to create your stub, you mock each level individually.
#Spy private Person person = //retrieve person
#Mock private Name name;
#Test
public void testStubbed() {
doReturn(name).when(person).getName();
doReturn("Neil").when(name).getName();
assertEquals("Neil", person.getName().getFirstName());
}
You can get a little closer to the deep stubs you want by using doAnswer(RETURNS_DEEP_STUBS), but you can't override arbitrarily-deep method calls without taking care to stub their parent calls. I'd stick to manual single-level-deep mocks as you do in your answer, or use even less mocking if possible.
A spy's default behavior is to delegate to its real method call, which will typically return a real object (like your Name) and not a Mockito spy. This means that you won't normally be able to change those objects' behavior using Mockito: a spy isn't really the same class as the object being spied on, but rather is a generated subclass where every field value is copied from the spied-on value. (The copying is an important feature, because a delegating spy would have very unintutitive behavior regarding this, including for method calls and field values.)
Foo foo = new Foo();
foo.intValue = 42;
foo.someObject= new SomeObject();
Foo fooSpy = Mockito.spy(foo);
// Now fooSpy.intValue is 42, fooSpy.someObject refers to the exact same
// SomeObject instance, and all of fooSpy's non-final methods are overridden to
// delegate to Mockito's behavior. Importantly, SomeObject is not a spy, and
// Mockito cannot override its behavior!
So this won't work:
doReturn("Neil").when(person).getName().getFirstName();
// Mockito thinks this call ^^^^^^^^^ should return "Neil".
And neither will this:
doReturn("Neil").when(person.getName()).getFirstName();
// The object here ^^^^^^^^^^^^^^^^ won't be a mock, and even if Mockito
// could automatically make it a mock, it's not clear whether that
// should be the same spy instance every time or a new one every time.
In your situation, I'd choose the following, in order from most preferable to least:
Create a real Name object and install it using doReturn. It looks like Name is a data object (aka value object) after all, which likely means it has no dependencies, solid behavior, and difficult-to-mock state transitions. You may not be gaining anything by mocking it.
Create a mock Name and install it as you do in your answer. This is particularly useful if Name is more complicated than it looks to be, or if it doesn't actually exist in the first place.
Replace getName to return a deep stub...
doAnswer(RETURNS_DEEP_STUBS).when(person).getName();
...which you can then override...
doReturn("Neil").when(person.getName()).getFirstName();
...even for arbitrarily deep values.
doReturn("Gaelic").when(person.getName()
.getEtymology()
.getFirstNameEtymology())
.getOrigin();
As a final editorial, one of the hazards of partial mocks is that it makes it really hard to tell which behavior is real and which is faked; this might make it hard for you to guarantee that the behavior you're testing is prod behavior and not mock behavior. Another hazard of deep stubbing is that you may be violating the Law of Demeter by definition. If you find yourself using this kind of technique often in tests, it may be time to consider rearchitecting your system under test.
#Test
public void listTypeTest() throws Exception {
doCallRealMethod().when(listType).setRecordCount(new BigInteger("556756756756"));
listType.setRecordCount(new BigInteger("556756756756"));
doCallRealMethod().when(listType).getRecordCount();
assertEquals(new BigInteger("556756756756"), listType.getRecordCount());
}

mockito when with third party class

I need to use a third party class in Mockito.when as parameter. The class does not have equals implementation and hence Mockito.when always returns null except the case where any() is used.
The below always returns null:
when(obj.process(new ThirdParytClass())).thenReturn(someObj);
however, this works
when(obj.process(any(ThirdParytClass.class))).thenReturn(someObj);
But, the problem is the process() method is called twice in the actual code and the use of any() is ambiguous and does not help in covering the multiple scenarios to test.
Extending the class does not help and also leads to other complications.
Is there a way to address the issue.
If a class doesn't implement a (sensible) equals(Object), you can always match instances yourself by implementing your own ArgumentMatcher. Java 8's functional interfaces make this pretty easy to write (not that it was such a big hardship in earlier versions, but still):
when(obj.process(argThat(tpc -> someLogic()))).thenReturn(someObj);
More often than not, however, if you just want to compare the class' data members, the built-in refEq matcher would do the trick:
ThirdParytClass expected = new ThirdParytClass();
// set the expected properties of expected
when(obj.process(refEq(expected))).thenReturn(someObj);
Mockito provides the captor feature that may help you to bypass limitations of equals() method because overriding equals() to make a test pass may be desirable but it is not always the case.
And besides, sometimes, equals() may not be overridable. It is your use case.
Here is a example code with an ArgumentCaptor :
#Mock
MyMockedClass myMock;
#Captor
ArgumentCaptor argCaptor;
#Test
public void yourTest() {
ThirdPartyClass myArgToPass = new ThirdPartyClass();
// call the object under test
...
//
Mockito.verify(myMock).process(argCaptor.capture());
// assert the value of the captor argument is the expected onoe
assertEquals(myArgToPass , argCaptor.getValue());
}

Mockito match specific Class argument

I am trying to mock some resources that are generated dynamically. In order to generate these resources, we must pass in a class argument. So for example:
FirstResourceClass firstResource = ResourceFactory.create(FirstResourceClass.class);
SecondResourceClass secondResource = ResourceFactory.create(SecondResource.class);
This is well and good until I tried to mock. I am doing something like this:
PowerMockito.mockStatic(ResourceFactory.class);
FirstResourceClass mockFirstResource = Mockito.mock(FirstResourceClass.class);
SecondResourceClass mockSecondResource = Mockito.mock(SecondResourceClass.class);
PowerMockito.when(ResourceFactory.create(Matchers.<Class<FirstResourceClass>>any()).thenReturn(mockFirstResource);
PowerMockito.when(ResourceFactory.create(Matchers.<Class<SecondResourceClass>>any()).thenReturn(mockSecondResource);
It seems like the mock is being injected into the calling class, but FirstResourceClass is being send mockSecondResource, which throws a compile error.
The issue is (I think) with the use of any() (which I got from this question). I believe I have to use isA(), but I'm not sure how to make that method call, as it requires a Class argument. I have tried FirstResourceClass.class, and that gives a compile error.
You want eq, as in:
PowerMockito.when(ResourceFactory.create(Matchers.eq(FirstResourceClass.class)))
.thenReturn(mockFirstResource);
any() ignores the argument, and isA will check that your argument is of a certain class—but not that it equals a class, just that it is an instanceof a certain class. (any(Class) has any() semantics in Mockito 1.x and isA semantics in 2.x.)
isA(Class.class) is less specific than you need to differentiate your calls, so eq it is. Class objects have well-defined equality, anyway, so this is easy and natural for your use-case.
Because eq is the default if you don't use matchers, this also works:
PowerMockito.when(ResourceFactory.create(FirstResourceClass.class))
.thenReturn(mockFirstResource);
Note that newer versions of Mockito have deprecated the Matchers name in favor of ArgumentMatchers, and Mockito.eq also works (albeit clumsily, because they're "inherited" static methods).

Mockito Mock a method call called twice

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

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