I have some Mockito behaviors defined and I also have verboseLogging turned on trying to debug why my test is failing. I see in the log that some of the methods are being called with either empty or null parameters, which I am not doing.
DataTypeService dataTypeService = Mockito.mock(DataTypeService.class, withSettings().verboseLogging());
when(dataTypeService.isMultivalued(anyString())).thenReturn(true);
I see this in the log:
dataTypeService.isMultivalued("");
invoked: -> at com.example.rest.service.api.v3.impl.ContentServiceImplTest.getDocumentBySchemaMultiValueTest(ContentServiceImplTest.java:186)
has returned: "false" (java.lang.Boolean)
I see something similar in the log for all of my other when statements as well. They return null instead of what I have in the thenReturn and then it continues and returns the proper item on a second call; however, I am only calling it once. Does defining a when statement, execute it under the covers with no params?
Does defining a when statement, execute it under the covers with no
params?
Kind of. When you use anyString() Mockito puts some internal state and then returns a default value (as stated in the anyString() Javadoc).
After doing that, it calls the mocked object with the default value returned by the Matcher, recording its calling internally to associate with a posterior call to thenReturn or thenThrow. But a mock with no recorded state yet will return a default answer, which is false in your case. So when you verboseLogging() it logs the recording call, printing the first false. But, after the recording, your mock is good to go, returning the expected value in the second and subsequent calls. Therefore, what you're seeing is just Mockito being Mockito, nothing wrong with that. :)
Related
Imagine you have method someMethod, how would you go by to test it?
Mockito.when(someClass.someMethod(someParam)).thenReturn(someValue);
var bar = foo() // SUT: ends upp calling someMethod somewhere in the stack
assertThat(bar).isEqualTo(someValue);
vs
Mockito.when(someClass.someMethod(someParam)).thenReturn(someValue);
var bar = foo() // SUT: ends upp calling someMethod somewhere in the stack
verify(someClass, times(1)).someMethod(someParam)
assertThat(bar).isEqualTo(someValue);
It is true that the Mockito.when is "kind of" verifying that someClass.someMethod is being called with the correct arguments. Personally I like the idea of having clear assertions/verifications so that the tests can serve as a form of documentation. I don't like giving my mocks double-responsibilities, I want to keep my mocks just simply as "mocks".
So back to my question.
What is the preferred way, using Mockito.when combined with Mockito.verify or only Mockito.when?
When defines the behaviour of the Mock - declaratively defining the way the mock will respond when methods are invoked with different parameters.
Verify is used to check whether the Mock has been interacted with in various ways.
Here are some URLS to the official Mockito documentation, which I hope will help.
Stubbing - with when
Argument matchers
Verification in order
Making sure interaction(s) never happened
on mock
It's probably worth performing a search for some other examples.
I think this question has been answered in https://stackoverflow.com/a/35301264/473064.
The summary is:
In short, it is considered good Mockito style to explicitly verify only the interactions that can't be implied from well-crafted stubs and postcondition assertions. They may be good calls for otherwise-unmeasurable side effects—logging code, thread executors, ArgumentCaptors, multiple method calls, callback functions—but generally should not be applied to stubbed interactions.
One point that I would add is that sometimes if we want to do a verifyZeroInterations to ensure that no unexpected calls occurred, we would have to first exhaust the known calls by verifying them.
What I usually do is to perform the simplest verify(mock, times(n)).someMethod(anyClass()) as generally as possible without repeating the more specific argument matching that I have already specified in the stubbing, which reduces the duplication as much as possible.
Example:
when(someObject.someMethod(eq("abc"))).thenReturn(someValue);
when(someObject.someMethod(eq("def"))).thenReturn(otherValue);
when(someObject.someMethod(endsWith("suffix"))).thenReturn(anotherValue);
var bar = foo();
assertEquals(expectedBar, bar);
verify(someObject, times(3)).someMethod(anyString());
verifyZeroInteractions(someObject);
Regarding your concern in the comment:
The problem I see is, if a new developer reads the test, they won't know the subbed method is part of the verification process.
The stubbed method is not part of the verification process. It's part of the test case setup, i.e., the Given step.
I think your example might be a little bit misleading. The final output from foo() is usually a transformation of the response from someMethod, i.e., someValue in the example. So if the stubbed method is not called and returned with the correct value, the test would have failed anyway. The said developer would then have to look at the mocking and understand how the test case works.
In the updated example below, there is no need to verify that someMethod is called because if it didn't get called, the assertion would fail.
Mockito.when(someClass.someMethod(someParam)).thenReturn(someValue);
var bar = foo() // SUT: ends upp calling someMethod somewhere in the stack
var expectedValue = // a value depending on `someValue`
assertThat(bar).isEqualTo(expectedValue);
In Mockito when we try to mock a method call, let's say we configure something like this
when(exampleClass.getOutputString(anyString())).thenReturn("output1");
This is all understandable. But my question is what is the reason this thenReturn("output1") method returns an OngoingStrubbing object (same as what when(exampleClass.getOutputString(anyString())) method returns), so that we can do something like this
when(exampleClass.getOutputString(anyString())).thenReturn("output1").thenReturn("output2");
or
when(exampleClass.getOutputString(anyString())).thenReturn("output1").thenThrow(new IllegalArgumentException());
However, both the above cases, when using the mock, it only returns "output1" and that's all the story. Anyone knows, why this chaining feature is present, and what are the uses of it? Kind of same thing applies to doReturn() too.
This means for the first call gives ouput1 and in the second call gives output2, and so on.
when(exampleClass.getOutputString(anyString())).thenReturn("output1").thenReturn("output2");
, The second one you need to reach one condition in the target test class so gives
output1 for the first case but in the second one you want to fail to test for example
try-catch clause or see if the code cover the broken scenarios like exceptions
when(exampleClass.getOutputString(anyString())).thenReturn("output1").thenThrow(new IllegalArgumentException());
I'm testing a method that call same method (db.getData()) twice. But I must return two different values.
Mockito.when(db.someMethod()).thenReturn(valueOne).thenReturn(valueTwo);
Then I tried out multiple thenReturn().
Unfortunately I'm getting only valueTwo for first & second db.getData() method call.
You are not showing a lot of context but here are some ideas:
make sure db is really a mock object
use the debugger to check if db.someMethod() is called twice as you expect
You can also use thenReturn(valueOne, valueTwo); although that should not make a difference
I suspect that your method is called more than twice and that you are missing the first invocation (which returns valueOne) and only looking at subsequent invocations (which will all return valueTwo).
See the API:
//you can set different behavior for consecutive method calls.
//Last stubbing (e.g: thenReturn("foo")) determines the behavior of further consecutive calls.
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
It's probably you are debugging and when you want to fetch the data of the breakPoint line, you are fetching from mock, so it will return one of it's thenReturn() parameters, so when you resume the test, it will test it with the second parameter.
I recommend you if you doubt it's working properly, one time fetch all thenReturn() items and after that you agree they're OK, start the test again with no tracing thenReturn() items.
I'm basically trying to verify whether the correct parameters are being invoked in a method.
Here's a snippet of the code I'm trying to test:
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.in("type", Arrays.asList("employee", "supervisor");
Verifying this using:
Mockito.verify(mockSession).createCriteria(User.class);
Mockito.verify(mockCriteria).add(Restrictions.in("type", Arrays.asList("employee", "supervisor"));
The first verify statement works. The second doesn't because, I believe, that the JVM detects two different List objects being compared to. However, when I change the second verify statement to:
Mockito.verify(mockCriteria).add(Restrictions.in("type", Mockito.anyList());
It works like a charm. However, I do want to ensure that the two Strings, employee and supervisor, are inside the List and that won't happen by using Mockito.anyList().
How do I get this to work?
EDIT: Please take note that I do not wish to only verify whether a List has been passed. I want to ensure that the correct Strings are passed inside that List as well
Unfortunately, here you cannot easily check what you want to check with matchers.
Mockito matchers work via side-effects, where a call to a matcher tells Mockito to use the matcher rather than testing equality. That means that Mockito matchers don't work at all when nested within objects like Criterion.
verify(mockCriteria).add(
Restrictions.in("type", Arrays.asList("employee", "supervisor"));
In the above, you don't use matchers, you're verifying that mockCriteria.add is called with an object that equals the Criterion you specify. However, if the returned Criterion doesn't override equals (and hashCode) then it will only test that the instances are the same—which will never be true here, because you're creating a new one in the verify statement.
verify(mockCriteria).add(Restrictions.in("type", anyList()));
Here, it looks like you're verifying that mockCriteria.add is called with any list, but anyList() actually tells Mockito to skip checking for one parameter and returns the dummy value null. You then create a Criterion where "type" in null, and then Mockito sees one any matcher on the stack for a one-argument method call, discards the newly-created invalid Criterion, and just checks that add was called at all. It looks like everything's working, but your mockCriteria could receive literally any parameter including null and the test would still pass. (If you were using a second matcher, or if add took two parameters, you would get InvalidUseOfMatchersException instead of your false positive.)
To make this work with Mockito matchers, you would need to write your own Hamcrest matcher that matches the entire Criterion, and then use argThat to let Mockito match arguments with it.
As Andy Turner mentioned, one way to solve this is to use ArgumentCaptor:
ArgumentCaptor<Criterion> captor = ArgumentCaptor.forClass(Criterion.class);
verify(mockCriteria).add(captor.capture());
Criterion criterion = captor.getValue();
// assert against criterion
However, be warned that this may be of limited use: Criterion doesn't have a lot of properties you can inspect. You may need to use toString(), as in this SO question.
I am using EasyMock to unit test my Java code. The class I'm trying to test is a RESTful webservice API layer. The API has an underlying service layer which is being mocked in the API test. My problem is figuring out how to correctly unit test my editObject(ID, params...) API method, since it calls service.getById() twice and expects a different object to be returned with each call.
editObject(ID, params...) first tries to grab the object from the service layer to make sure the ID is valid (first service.getById(ID) call to expect, returns original unmodified object). Next it modifies the parameters specified in the API call, saves it to the service, and calls get again to hand the caller the service-managed modified object (second service.getbyId(ID) call to expect, returns modified object).
Is there a way to represent this with EasyMock?.
Sure, you can do two different things for two method calls with the same method and parameters. Just declare your expectations in the order you expect them to happen and set up the responses accordingly.
expect(mockService.getById(7)).andReturn(originalObject).once();
expect(mockService.getById(7)).andReturn(modifiedObject).once();
replay(mockService);
The .once() is optional but I find in this case that it's more self-documenting.
You can chain multiple andReturn method calls:
EasyMock.expect(service.getById(1))
.andReturn(firstObject)
.andReturn(secondObject);
The first time service.getById is called with 1 as argument the mock will return firstObject and the second time secondObject. You can chain as many as you want and even throw an exception via andThrow for a specific call.
This technique is also helpful in conditional expressions in which you may want to invalidate the first condition but pass the second one or vice-a-versa.