While mocking a method, which have complex type, returning null in java
public void sendRequest(OnlineRequest request) {
OnlineResponse response = client.handleRequest(request);
System.out.println( response);
}
Mockito.when(client.handleRequest(request)).thenReturn(new OnlineResponse());
If I understand correctly, your issue is that System.out.println(response); prints null?
This is most likely due to the fact that client.handleRequest() is not being called with the request you expect. This may be an error somewhere in code you haven't provided us, OR it may simply be due to the fact that OnlineRequest does not have an implementation of equals/hash-code, so when() is never triggered because it is not called with the exact same instance of OnlineRequest as you use in your unit tests.
You might wish to test that handleRequest is called with exactly the object you expect. This can be accomplished using verify():
verify(client).handleRequest(request);
in your unit test. This too is dependent on the equals/hash-code implementation to determine whether request is the expected parameter or not.
Related
No matter what I do, I get the following error when trying to mock a method
java.lang.IllegalStateException: missing behavior definition for the preceding method call:
ConfigurationSection.get("country-language")
Usage is: expect(a.foo()).andXXX()
My code for testing:
EasyMock.expect(section.getString("country-language")).andReturn("US");
LocaleManager.updateLocale(section, Collections.emptyList());
EasyMock.expectLastCall();
replayAll();
Assert.assertEquals("Test", TranslatedMessage.translate("test"));
verifyAll();
The expect andReturn is called for the mocked class, and the static upateLocale method calls the method, first thing.
The strange thing is this test works fine:
EasyMock.expect(section.getString("country-language")).andReturn("US");
replayAll();
Assert.assertEquals("US", section.getString("country-language"));
verifyAll();
But calling it from an external method doesn't work.
Your mock says:
EasyMock.expect(section.getString("country-language"))
The error says:
ConfigurationSection.get("country-language")
You are not mocking get("country-language"). You are mocking getString("country-language").
Unrelated, but verify is a maintenance nightmare and should generally be avoided. This ties test code directly to an implementation. Tests should focus on inputs and outputs if at all possible.
I am new to JUnit mockito, I have this test function written for my Spring rest resource.
#Test
public void getAllMessageHappyTest() throws Exception {
List<Message> messageList = new ArrayList<>();
messageList.add(new Message(1,"Hello"));
messageList.add(new Message(5,"Hello world"));
messageList.add(new Message(3,"Hello World, G!"));
when(messageService.getAllMessages()).thenReturn(messageList);
RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/messages/").accept(MediaType.APPLICATION_JSON);
MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn();
String expected = ""; // expected
JSONAssert.assertEquals(expected,mvcResult.toString(),false);
}
In the above scenario, I have the when(messageService.getAllMessages()).thenReturn(messageList); returning the messageList which is written by me(or by member of team) and I am comparing the returned JSON with the String expected which will also be written by me(or by the same member of team). So both the things are written by the same guy, so what is the point of having such kind of tests.
If I understand the question correctly the concern is this; because the person who writes the test also hardcodes (in the form of a JSON string) the expectation the test may be redundant or at least may be of limited value. Perhaps the sub text to your question is that since whoever wrote the underlying endpoint will provide the expectation then it must pass and if its success is preordained then it is of little value.
However, regardless of who writes the test and who writes the code-under-test, the example test you showed above has value because:
It tests more than the retuned JSON, it also tests ...
That the REST endpoint mapping is correct i.e. that it exposes an endpoint named "/messages/" which accepts JSON
The REST layer is using a serialiser which produces some JSON
Continued running of this test case will ensure that the expected behaviour of this endpoint continues to be met even after you (or some other member of your team) are no longer working on this code or, in other words; it acts as a regression safety net.
The code-under-test may be changed in future, if so then this test case provides a baseline against which future development can take place.
The test case provides a form of documentation for your code; people who are unfamiliar with this codebase can review the tests to understand how the code is expected to behave.
In addition, this test case could be extended to include tests for sad paths such as invalid repsonses, unsecured access attempts etc thereby improving test coverage.
Update 1: in response ot this comment:
even if someone makes changes in an actual code and now after making actual code is producing a different kind of JSON(say not as required) even then too test case will pass because when then is hardcoded and expected is also hardcoded. So what is the point?
A test like this clearly makes no sense:
String json = "...";
when(foo.getJson()).thenReturn(json);
assertEquals(json, foo.getJson());
Bu that is not what your test does. Instead your test asserts that the response - in the form of JSON - matches the serialised form of the response returned by your mocked messageService.getAllMessages(). So, your test covers the serialisation piece along with the various aspects of the Spring MVC layer such as the endpoint->controller mapping and interceptors and filters (if you have any).
I want to use mockito spy.
When I set a return value in both following ways:
when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate));
doReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate)).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
I see the return value is being evaluated eagerly
meaning when this "setting" line is executed.
how can i force the spy to evaluate the return value only on demand?
meaning when the "when" condition is met.
update
Thanks to #RobbyCornelissen I have tried this code:
when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
ImagesSorter mock = (ImagesSorter)invocation.getMock();
return mock.sortImages((List<Image>)args[0], (UserInfo)args[1], fakeNowDate);
}
});
But it didn't help:
1) the "when" expression was invoked immediately. (not wanted)
2) eventually the callback wasn't call.
First let me warn you on partial mocks, because that is what the code is actually doing, it's wrong design wise. It may be more relevant to use a strategy pattern to compose behavior of the tested subject. Mockito team (including me) strongly advises to stay away of partial mocks whenever possible.
EDIT : I don't know the code and I don't know exactly which component under test but from what I gather there's a type responsible to sort images, let's call it ImagesSorter.
So first case ImagesSorter is a dependency of a test subject, so in this case just stubbing the mock of ImagesSorter will do.
If however it is ImagesSorter itself under test, and stubbing a special method of this class is called a partial mock and it is plain wrong. It exposes internal of the production code in the test. So there's several solutions.
As the code snippet showed in the answer shows a fakeDate, one of the solution is to not use things like new Date() and code a simple class TimeSource whose sole responsibility is to provide a date. And in tests the bwhavior of this TimeSOurce could be overriden.
A simplier solution would be to use JodaTime as it provides this functionality built in.
If the scope of test goes beyond changing the date, then maybe ImagesSorter needs a way to be configured with other objects. Inspiration on how to do it can be found with the cache builder of guava. If the configuration is dead simple then a simple constructor coud do it.
That could look like :
class ImagesSorter {
ImagesSorterAlso algo;
ImagesSorter(ImagesSorterAlgo algo) { this.algo = algo; }
Iterable sortImages(...) {
algo.sort(...);
}
}
interface ImagesSorterAlgo {
Iterable sort(...);
}
Now about your questions :
1) the "when" expression was invoked immediately. (not wanted)
It is expected imagesSorterSpy is a spy so by default it calls the real code. Instead you should use the alternate API, the same that #RobbyCornelissen showed. i.e.
doAnswer(sortWithFakeDate()).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
// with BDD aliases (BDDMockito) which I personnaly finds better
willAnswer(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
will(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
sortWithFakeDate() would a static factory method that returns the answer, so the code reads well, and maybe reused elsewhere.
2) eventually the callback wasn't call.
This issue is most probably due to non equal arguments. You may need to check the equals method. Or relax the stub using the any() matcher.
I don't know the types of the arguments and classes you're using, so I can't provide a complete example, but you can stub using callbacks with the Answer<T> interface:
Mockito.doAnswer(new Answer() {
Object answer(InvocationOnMock invocation) {
ImagesSorter mock = (ImagesSorter) invocation.getMock();
Object[] args = invocation.getArguments();
return mock.sortImages((List<Image>) args[0], (UserInfo) args[1],
fakeNowDate);
}
}).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
I have the following code:
handler = NodeHandler.getINodeHandler(localZone).getITspPlatformHandler().getITspProcessorManagementHandler();
I mocked this out this way:
mockStatic(NodeHandler.class);
INodeHandler iNodeHandler = mock(INodeHandler.class,Mockito.RETURNS_DEEP_STUBS);
when(NodeHandler.getINodeHandler(localZone)).thenReturn(iNodeHandler);
ITspProcessorManagementHandler iTspProcessorManagementHandler =mock(ITspProcessorManagementHandler.class,Mockito.RETURNS_DEEP_STUBS);
when(iNodeHandler.getITspPlatformHandler().getITspProcessorManagementHandler()).thenReturn(iTspProcessorManagementHandler);
After a few row of code an another chained method call comes:
ITspTrafficProcessor processor = NodeHandler.getINodeHandler(localZone, localUI).getITspPlatformHandler().getITspProcessorManagementHandler()
.getITspProcessorHandler(procs[i]).getITspTrafficProcessorHandler(0).getAttributes();
And i mocked this out this way:
when(NodeHandler.getINodeHandler(localZone,UI.CORBA)).thenReturn(iNodeHandler);
when(iNodeHandler.getITspPlatformHandler().getITspProcessorManagementHandler()(+1+).getITspProcessorHandler(anyString())
.getITspTrafficProcessorHandler(anyInt()).getAttributes()).thenReturn(null);
So my question is that, i can not find a better solution than this, because the problem is if i tell the mockito to return null to the handler instead of iTspProcessorManagementHandler then i get a nullpointer exception at (+1+), but if i do the following changes to my code:
INodeHandler iNodeHandler = mock(INodeHandler.class,Mockito.RETURNS_MOCKS);
Than mockito mocks out every method call, and my when-thenReturn statements does not returns what i want for example null. So any advice to do a better solution????
Messy mocking like that is an indication that you could improve abstraction. I'd consider encapsulating that particular logic in a helper interface/class, or to inject the expected type returned by the "trainwreck" to the method/class.
I am using easyMock for JUnit testing. I want to test a method which gets a Project object as its arguments and sets the modify date of that project and persists it in db.
So e.g.
public void setProject(Project project) {
project.setModifyDate(new Date());
this.reporsitory.persist(project);
}
Now at my test method I have tow mocked projects. For one of them I have set the return value of the getModifyDate. For the other mocked project object I just call the setProject(mockedProject); Now I assertEqual these two project objects.
The problem is easymock throws me an error at the project.setModifyDate(new Date()) of the class which I am testing.
Exception : Unexpected method call project.setModifyDate(..).. Expected:1, Actual:0.
It seems that it does not expect the setter method. Could you please let me know what I am doing wrong.
Thanks.
Yes, it is because of the type of mock object you created. It expects your code to call every method you defined when the one call executes. I cannot remember the exact name but i think it is something like nicemock, versus a strictmock whick makes your code execute every expected method. You should use EasyMock.createNiceMock() for your mock object. The error you have is because it expects you to call setModifyDate but your code didn't for that call.
Your call is unexpected because you must have not put EasyMock.expected for that method. You need to add your mock object .expected(getMethod).andReturns(something).