Java & Mockito - passing an argument to a method AND capturing the result - java

I'm trying to fix some existing junit/mockito tests that I've had to alter due to a re-write to use Dao's.
So I have this argument captor :-
ArgumentCaptor<CustomerDao> customerDaoCaptor = ArgumentCaptor.forClass(CustomerDao.class);
and I've used this approach before to get the (customer) object so that I can perform more tests on it. I would usually use it like this :-
verify(customerDao, times(1)).saveOrUpdate(customerDaoCaptor.capture());
so that I can then run tests like :-
Customer customerActual = (Customer) customerDaoCaptor.getAllValues().get(0);
assertEquals("PRE", customerActual.getExistingCustomer());
However in this instance I'm not calling the saveOrUpdate method (that the captor is bound to), but another Dao method that takes a unique key as a parameter that ultimately updates the customer record by using sql - ie it doesnt use the parent object's (Hibernate) saveOrUpdate method.
I know that I can test that its called, eg :-
inOrder.verify(customerDao, times(1)).updateRegisterStatusToCurrentByCustomerNumber(CUSTOMER_NUMBER);
so I'm trying to somehow assign/bind the captor to the 'updateRegisterStatus....' method, but I cant seem to find a way to do it, mainly because that method must take a string param, customer_number.
So in essence I'm trying to do this :-
inOrder.verify(customerDao, times(1)).updateRegisterStatusToCurrentByCustomerNumber(CUSTOMER_NUMBER).customerDaoCaptor.capture()
which obviously doesn't work...
As a lot of googling hasn't helped me, I'm guessing that I'm doing it completely wrong.
Update - #SpaceTrucker
I've tried the following code as you suggested :-
CapturingMatcher<String> capturingMatcher = new CapturingMatcher<String>();
verify(customerDao, times(1)).updateRegisterStatusToCurrentByCustomerNumber(
argThat(
org.hamcrest.Matchers.allOf(capturingMatcher, org.hamcrest.Matchers.notNullValue())
)
);
List<String> values = capturingMatcher.getAllValues();
based on my Dao implementation :-
public void updateRegisterStatusToCurrentByCustomerNumber(String customerNumber)
and it does pass the test successfully, in that it doesn't fail, but it doesnt do everything what I need it to. The ideal goal here is to somehow get an object representing the updated customer object - eg :-
Customer customerActual = (Customer) values.get(0);
assertEquals("value", customerActual.getExistingCustomer());
However the values object is empty and on debugging the test I can confirm that the method in question is being called.
Apologies in advance if there's something trivial that I've missed here, and once again, thanks for all your help!

This problem seems to more difficult than first thought about. See below for more details on this.
The Matcher instance Mockito does need to see has to implement the CapturesArguments interface. So the solution is to implement an AndMatcher that will delegate to its child matchers and implements CapturesArguments. It will delegate to all child matchers that also implement CapturesArguments when CapturesArguments.captureFrom(Object). Please note that CapturesArguments is a Mockito internal interface.
The following solution does not work,
because the Matcher instance Mockito sees, doesn't implement the CapturesArguments interface and therefore won't delegate the argument capturing to the CapturingMatcher.
The ArgumentCaptor uses a CapturingMatcher internally. So you could use Mockito.argThat with a combined matcher that will consist of a CapturingMatcher and any other matcher you like.
For example given the interface
public interface ProductService {
List<Product> getProductsForCategory(Category category);
}
then we can do the following:
import org.hamcrest.Matchers;
// ...
CapturingMatcher<Category> capturingMatcher = new CapturingMatcher<Category>();
Mockito.verify(productService).getProductsForCategory(Mockito.argThat(Matchers.allOf(capturingMatcher, Matchers.notNullValue())));
List<Category> values = capturingMatcher.getAllValues();
You could also implement your own ArgumentCaptor with a capture method that will take an additional matcher instance.

Your question isn't entirely clear, but I'm getting the following points from it:
You have a mock of a CustomerDao.
Your test (indirectly) calls the updateRegisterStatusToCurrentByCustomerNumber() method of this mock, passing a String identifier to it.
updateRegisterStatusToCurrentByCustomerNumber() does something internally to a Customer object.
You want to test things about the Customer object in question.
If these are correct, then you have a fundamental misunderstanding of how mocks work. That internal code that does something to a Customer object? In this test, that code doesn't exist. It's never called. The mock version of CustomerDao responds to your updateRegisterStatusToCurrentByCustomerNumber() call by simply returning what your test setup code told it to, whether that's null, a carefully crafted sample object, or another mock. It never invokes the actual CustomerDao code because the whole point of a mock is to make your test not be dependent on that code, so that bugs in that code don't cascade test failures throughout the dependency tree.
To test the internal behavior of CustomerDao.updateRegisterStatusToCurrentByCustomerNumber(), you will need to create separate tests that directly call CustomerDao methods on a non-mock CustomerDao, with everything else being mocks.

Related

How to verify a fluent interface mock chain with specific args

Before this gets marked as duplicate, I've gone through all topics on SO that I could find and I did not see anything close to what I am trying to achieve.
I'm working on writing Unit tests for several so called 'fluent' interfaces and I am facing difficulties verifying the chain of method calls without making it too complex and unreadable. Perhaps, I thought I was missing out on something and I am just trying to reinvent the wheel. How would I go about that?
Having a mocked object MyQuery mockedQuery, I'd like to achieve the following:
MyQuery nameQueryMock = Mockito.mock(MyQuery.class);
Mockito.doReturn(nameQueryMock).when(mockedQuery)
.name("SPECIFIC NAME");
MyQuery addressQueryMock = Mockito.mock(MyQuery.class);
Mockito.doReturn(addressQueryMock).when(nameQueryMock)
.address("SPECIFIC ADDRESS");
Mockito.doReturn(JOHN_QUERY_RESULT).when(addressQueryMock)
.singleResult();
What I was hoping to do is more like:
Mockito.when(mockedQuery.name("SPECIFIC NAME").address("SPECIFIC ADDRESS").singleResult()).thenReturn(JOHN_QUERY_RESULT);
But I found out that is not how it works. I tried playing around with the Answers provided by Mockito (RETURNS_DEEP_STUBS was one of the things I tried) but I found out it worked only on the last method call of the chain as pointed out in the docs. In my case, I need to return JOHN_QUERY_RESULT only when both the name() method is passed "SPECIFIC NAME" and address() is passed "SPECIFIC ADDRESS".
I expect to be able to achieve this in a more neat way, as my chains include a lot more methods and taking the first approach overloads my tests with a lot of code which I hope to avoid.
What am I missing here?
Update:
Some background:
There's a MyService which provides a createQuery() method that returns a new instance of MyQuery. This service (MyService) is used in a class I am trying to test, this class does some job, but it makes use of (those) queries to retrieve information about something that it has to do. Therefore mocking MyService and Injecting it in the tested class, also using a mocked MyQuery will allow me to test the behavior itself eliminating the internal implementation of MyQuery, just by being able to specify what the return should be on SPECIFIC query searches.
Based on your background info I came up with the following example:
(so that might be totally off base from your real case)
Lets say your TestClass has a method like this
public String someMethod(String name, String address) {
return service.createQuery().name(name).address(address).singleResult();
}
and the test for it would look like that:
#InjectMocks
TestClass testClass;
#Mock
MyService service;
#Test
public void test() {
MyQuery query = Mockito.mock(service);
when(service.createQuery()).thenReturn(query);
Mockito.when(mockedQuery.name("SPECIFIC NAME")
.address("SPECIFIC ADDRESS")
.singleResult())
.thenReturn("JOHN_QUERY_RESULT");
Assert.assertEquals("JOHN_QUERY_RESULT", testClass.someMethod("SPECIFIC NAME", "SPECIFIC ADDRESS"));
}
In my case, I need to return JOHN_QUERY_RESULT only when both the name() method is passed "SPECIFIC NAME" and address() is passed "SPECIFIC ADDRESS".
That part would already be covered by the test, simply by the fact that if the mocks would not match you would get an NullPointerException instead.
Also it sounds like something that isn't relevant for a UnitTest of the TestClass, but instead should be relevant for a UnitTest of MyQuery.
However lets have a look at the test. We can see that every line of the test includes a operation based on a mock.
What have we achieved with that test? Did we test the TestClass?
No. We could have just mocked the whole TestClass instead and return the result directly. And mocking the TestClass is bad.
So my answer to that is: Nothing.
We have verifed that mockito does what is supposed to do, and chaining method calls work, but that is beyond the point of a good test.
What can we do to improve this?
I'd say a test like that is not really cut out for a UnitTest, even less for mocking, instead we should focus on an integration test.
In case MyQuery#singleResult has some 3rd party interactions, for example with a database, then this is something that could be mocked.
However in the end we would still need another Integration-Test for the database interaction. In that case we might be better of by restricting ourselves to only test some Exceptions that are normally to hard to reproduce.

Unit testing method parameter verification best practice

What is the best practice for verifying a method call with complex parameters when unit testing?
Say I'm testing a function like this:
class ClassA {
ClassB dependency;
void someFunction(SomeInputForA input) {
// do some thing
dependency.anotherFunction(differentInput);
}
}
The two options that I can think of for verifying that someFunction calls anotherFunction with the proper input are:
A) do a verify on the mock of dependency for calling anotherFunction
unitUnderTest.dependency = mockClassB;
InputClass expectedDifferentInput = ... ;
verify(mockClassB).anotherFunction(expectedDifferentInput);
B) do an argument captor on the call of anotherFunction and assert the properties
unitUnderTest.dependency = mockClassB;
ArgumentCaptor<InputClass> captor = ArgumentCaptor.for(InputClass.class);
verify(mockClassB).anotherFunction(captor.capture());
InputClass capturedInput = captor.getValue();
assertEquals(value, capturedInput.param1);
// and more asserts afterwards
Is there a suggested path here? I'd lean towards the captor method because it feels more rigorous and is not relying on objects equals implementations being proper.
Thoughts?
Is differentInput computated off input?
If so then your B) is the better way to go as you are saying for Input A, you expect ClassA to change this to expectedDifferentInput and want to verify the delegating class (ClassB) is called. You are verifying the transformation of the input and delegating logic of ClassA.
If differentInput has no relation to input then you don't need to use the captor as really you are just checking delegation.
Any public caller to someFunction on ClassA shouldn't need to know about ClassB so it can be said both methods A) and B) are actually white box testing, in this case and so you might as well use the captors anyway. As you vary your input to someFunction, captors may also help you to identify edge cases if differentInput is computed off input.
You can always use matchers on the object passed into mockClassB.anotherFunction(). For example, if you want to compare fields on an object, you can write:
Matcher<YourClass> yourMatcher = Matchers.hasProperty("yourProperty", Matchers.equals(whatever));
verify(mockClassB).anotherFunction(argThat(yourMatcher));
I prefer this way, since you can share syntax for the when and the verify for the matchers and you can combine any combination of matchers. You just need to include the latest mockito and hamcrest libraries to get this to work.
I've used argument captors but VERY sparingly. The biggest issue you run into is that this route creates fragile unit tests. And no one is happy when they make a small change to a class and then find themselves struggling with unit tests in calling classes that shouldn't have been affected.
That being said, absolutely you have to eventually ensure that correct calls are made. But if you rely on an equals override working, then you are relying on that class having an equals method that works, and this is then part of that class's contract (and unit tested in that class) which is reasonable.
So that's why I'd vote for keeping it simple and just using verify. Same thing in the end, but your unit test is just less fragile.

mockito : mock method call with parameters by reflection

I'm using mockito and developping with java6 and spring.
I'm working on a test API for some developpers and I propose a few methods for mocking objects and methods (it's a legacy code...).
Now, I want to replace all this things by mockito but I always propose a test API. So, I developped some methods using mockito.
I have an old method with two parameters (String). A first parameter is a mocked service id and its method with parameters. And the second parameter is the returned Object.
Example :
mockReturnObject("myServiceId.myMethod(String, Integer)", myReturnedObject);
Now, I want to use mock, when and thenReturn mockito methods, and I don't see how...
Perhaps with reflection but with "when" method it's impossible because mockito need the effective method.
How can I do that ? thanks.
This is a bad idea: you're trying to reimplement some of the systems Mockito already provides while losing out on many of the features Mockito offers. However, there is a way to make this work, with some difficulty. The key is to write a custom Answer, make it the default answer for the mock, and then compare your object, method name, and method parameter types using InvocationOnMock.
public class ReflectiveMockAnswer implements Answer<Object> {
#Override public Object answer(InvocationOnMock invocation) {
// Assume you've successfully parsed each String into a StubbedResponse, with
// Object target, String method, String[] argTypes, and Object returnValue.
// A Set would beat a for-loop here, should you need to optimize.
for (StubbedResponse stubbedResponse : allStubbedResponses) {
if (stubbedResponse.target == invocation.getMock()
&& stubbedResponse.method.equals(invocation.getMethod().getName())
&& stringArraysEqual(stubbedResponse.argTypes,
typeNamesFrom(invocation.getMethod().getParameterTypes())) {
return stubbedResponse.returnValue;
}
}
throw new RuntimeException("Unstubbed method called.");
}
}
// Later...
Object yourMockObject = Mockito.mock(classToMock, new ReflectiveMockAnswer());
At that point, you've implemented a simplified version of Mockito within and based on the full version of Mockito. You'll also need to:
Parse the string into a StubbedResponse, probably with regular expressions
Identify the field in your bean-under-test by name
Replace that field with a mock of the appropriate class, created as above, before the bean-under-test has a chance to interact with it
...and acknowledge that this solution doesn't handle:
Verification
Any sort of argument matching, including basic "equals" matching
Name collisions in parameter types (com.foo.SomeClass vs com.bar.SomeClass)
Repeated calls (thenReturn(1, 2, 3).thenThrow(new RuntimeException()))
...and cannot handle:
Code search tools: you can only tell which methods are mocked other than by searching for strings, not with tools like "Find references" in Eclipse the way Mockito can
Compile-time checking and automated refactoring tools: your tests would break at runtime if field names, method names, or parameters change; Mockito doesn't have that problem
Final methods: Mockito can't, so you can't either
Unless this is a "straw man" or very temporary solution, I recommend strongly to just introduce Mockito directly into your test cases, one test at a time.

EasyMock void method

I'm trying to use EasyMock to mock out some database interface so I can test the business logic off a wrapping method. I've been going ok with methods that return by using the following in my setup of my test.
DBMapper dbmapper = EasyMock.createMock(DBMapper.class);
userService.setDBMapper(dbmapper);
then within my actual test I run
EasyMock.expect(dbmapper.getUser(userId1)).andReturn(mockUser1);
EasyMock.replay(dbmapper);
userService.getUser(userId1);
This service then connects to the dbmapper and returns the object (the mapper is injected using setter methods)
These type of mocks seem to work fine. However when I try to run a test for
userService.addUser(newUser1);
This method calls a void method.
dbmapper.createUser(newUser);
It's this method that I'm having problems mocking out.
I've tried the following
EasyMock.expectLastCall();
EasyMock.replay(dbMapper);
userService.addUser(newUser1);
as some other posts/questions etc seem to suggest I get an IlligalStateException: no last call on a mock available
Can anyone point me in the right direction please?
Many Thanks in advance
You're close.
You just need to call the method on your mock before calling expectLastCall()
So you expectation would look like this:
userService.addUser(newUser1);
EasyMock.expectLastCall();
EasyMock.replay(dbMapper);
userService.addUser(newUser1);
This works because the mock object is in Record mode before the call to replay(), so any calls to it will perform default behaviour (return null/do nothing) and will be eligible for replaying when the replay() method is called.
What I like to do to make sure that it is obvious the method call is for an expectation is to put a small comment in front of it like this:
/* expect */ userService.addUser(newUser1);
EasyMock.expectLastCall();
EasyMock.replay(dbMapper);
userService.addUser(newUser1);
This problem does not happens if you use the 'nice' API:
DBMapper dbmapper = EasyMock.createNiceMock(DBMapper.class);
There are two kinds of mock - strict and nice. The strict mock throws Assertion Error in case an unexpected method is called. The nice mock allows unexpected method calls on the mock.
For further details, refer to the official doc - http://easymock.org/user-guide.html#mocking-strict

Mockito: is it possible to combine mock with a method name to create a methodCall inside a when() call?

my first question on StackOverflow. I'd like to be able to do something like:
SomeClass mock = mock(SomeClass.class);
String methodName = "someMethod"; OR Method method = ...someMethod...
Both of these things (the mock and the method) would combine to do the following:
when(mock.someMethod()).thenReturn(null);
Of course, the 'null' value will be changed accordingly for my needs, but I am trying to determine two things:
1) Is it even possible to do something like this in Java? This = combining a class object and a method into a methodCall.
2) How do I do such a thing?
I've researched this endlessly and I can't find anything. The problem is that even if this works with a regular class and a regular method (someClass and someMethod would come together to do someClass.someMethod()), keep in mind that this has to work with a mock object for use inside a when() call.
ANSWERED: when(method.invoke(mock)).thenReturn("Hello world."); is the correct syntax and reflection indeed does work inside a when() call. Thanks Kevin Welker!
Since you basically asked me to repost my comment, modified by your response, as an answer, here it is:
Try using reflection as in:
when(method.invoke(mock)).thenReturn("Hello world.");
although, I'm not sure how this is working for you, since you cannot mock/spy class Method (it is final). Mockito's when() only works on mocks or spies. If this is really working for you, can you post a little more detail?
If it doesn't work, you can -- as I suggested in my comment in the OP -- go the CGLib route and bypass Mockito. It's really not that difficult as it looks at first. In my OSS project Funcito (not a mocking framework), I stripped down a lot of the Mockito CGLib proxying code and rewrote it for my needs. It gives a much simpler view into the world of proxying classes, and intercepting method calls.
ADDITIONAL RESPONSE TO COMMENTS
I see how this is working for you, but I am not sure you really understand how it is working. The reason this might matter is because future changes to the way Mockito itself works could render your solution broken in the future. In essence, the reason it works is almost accidental, but yes it will work.
The way that when() is supposed to work is that what happens in between the parentheses is a method call on a previously created Mockito-generated mock or spy, which is just a fancy proxy of a class, rather than a real instance of the class. The proxies have special logic that intercepts the fake proxied method call and basically add that to a list of registered proxy-method invocations (it is stored in something called an IOngoingStubbing or something like that) for later use. Since Java evaluates parameters before invoking a method, this guarantees that the proxied method call gets registered/remembered before the when() method is actually executed. What the when() does is pops off this IOngoingStubbing, which then becomes the object on which thenReturns() is called.
You are not using this "correctly" but it still works for you. How? Well, all that needs to happen is that a method on the proxy needs to be called in order to be registered in a IOngoingStubbing before when() gets executed. You are not directly invoking a method on a proxy, but you are indirectly invoking a method on a proxy by passing the proxy to Method.invoke(). Hence the criteria is satisfied, and when() already has a proxy-method-call registered in an IOngoingStubbing.
You can see the same kind of "accidental" happiness in the following code, which appears at first to make no sense until you realize how Mockito works:
#Test
public void testSomething() throws Exception {
List listMock = mock(List.class);
Method m = List.class.getDeclaredMethod("get", int.class);
m.invoke(listMock, Mockito.anyInt());
when(null).thenReturn("Hello World"); // Huh? passing null?
assertEquals("Hello World", listMock.get(0)); // works!
}
The above test actually passes! Even though the argument to when is null, what counts is that the proxy (i.e., mock) instance had the correct method invoked on it prior to the when statement being invoked.
While it is unlikely that Mockito will change the basic way things work under the covers, there is still the potential for this to break for you sometime in the future. Like I said, it is more or less a happy accident that it works. As long as you understand the way it works and the risk involved, more power to you.
I think, adding a new method after class initialization is not possible as long as the method is not specified in the interface or class provided to Mockito. You would change the class signature after initialization and this is something which is not possible.
For stub method calls have a look to: http://code.google.com/p/mockito/. There is a sample on stub method calls.
If you want to get dynamic answers, not static ones, you should not use Mockito. Use a fake object or a stub to get you behavior for testing. See: http://martinfowler.com/articles/mocksArentStubs.html for details on this issue.

Categories

Resources