I am mocking an object with Mockito, the same method on this object is called multiple times and I want to return the same value every time.
This is what I have:
LogEntry entry = null; // this is a field
// This method is called once only.
when(mockLogger.createNewLogEntry()).thenAnswer(new Answer<LogEntry>() {
#Override
public LogEntry answer(InvocationOnMock invocationOnMock) throws Throwable {
entry = new LogEntry();
return entry;
}
});
// This method can be called multiple times,
// If called after createNewLogEntry() - should return initialized entry.
// If called before createNewLogEntry() - should return null.
when(mockLogger.getLogEntry()).thenAnswer(new Answer<LogEntry>() {
#Override
public LogEntry answer(InvocationOnMock invocationOnMock) throws Throwable {
return entry;
}
});
The problem is, it seems that my getLogEntry method is called only once. For all subsequent invocations, null is returned instead and I get NPEs in tests.
How can I tell mockito to use stubbed version for all calls?
=================================================================
Post mortem for future generations
I did some additional investigation and as always it is not library's fault, it is my fault. In my code one of the methods called getLogEntry() before calling createNewLogEntry(). NPE was absolutely legitimate, the test actually found a bug in my code, not me finding bug in Mockito.
Your stub should work as you want it. From Mockito doc:
Once stubbed, the method will always return stubbed value regardless
of how many times it is called.
Unless I'm missing something, if you want to return the same object for each method invocation then why not simple do:
final LogEntry entry = new LogEntry()
when(mockLogger.createNewLogEntry()).thenReturn(entry);
when(mockLogger.getLogEntry()).thenReturn(entry);
...
verify(mockLogger).createNewLogEntry();
verify(mockLogger, times(???)).getLogEntry();
Mockito will return the same value for every matching call.
Am I missing something, or would the following suffice?
LogEntry entry = null; // this is a field
when(mockLogger.createNewLogEntry()).thenAnswer(new Answer<LogEntry>() {
#Override
public LogEntry answer(InvocationOnMock invocationOnMock) throws Throwable {
if (entry == null) {
entry = new LogEntry();
}
return entry;
}
});
when(mockLogger.getLogEntry()).thenAnswer(new Answer<LogEntry>() {
#Override
public LogEntry answer(InvocationOnMock invocationOnMock) throws Throwable {
return entry;
}
});
Only do the assignment if entry == null.
Related
I am using Mockito for service later unit testing. I am confused when to use doAnswer vs thenReturn.
Can anyone help me in detail? So far, I have tried it with thenReturn.
You should use thenReturn or doReturn when you know the return value at the time you mock a method call. This defined value is returned when you invoke the mocked method.
thenReturn(T value) Sets a return value to be returned when the method is called.
#Test
public void test_return() throws Exception {
Dummy dummy = mock(Dummy.class);
int returnValue = 5;
// choose your preferred way
when(dummy.stringLength("dummy")).thenReturn(returnValue);
doReturn(returnValue).when(dummy).stringLength("dummy");
}
Answer is used when you need to do additional actions when a mocked method is invoked, e.g. when you need to compute the return value based on the parameters of this method call.
Use doAnswer() when you want to stub a void method with generic Answer.
Answer specifies an action that is executed and a return value that is returned when you interact with the mock.
#Test
public void test_answer() throws Exception {
Dummy dummy = mock(Dummy.class);
Answer<Integer> answer = new Answer<Integer>() {
public Integer answer(InvocationOnMock invocation) throws Throwable {
String string = invocation.getArgumentAt(0, String.class);
return string.length() * 2;
}
};
// choose your preferred way
when(dummy.stringLength("dummy")).thenAnswer(answer);
doAnswer(answer).when(dummy).stringLength("dummy");
}
doAnswer and thenReturn do the same thing if:
You are using Mock, not Spy
The method you're stubbing is returning a value, not a void method.
Let's mock this BookService
public interface BookService {
String getAuthor();
void queryBookTitle(BookServiceCallback callback);
}
You can stub getAuthor() using doAnswer and thenReturn.
BookService service = mock(BookService.class);
when(service.getAuthor()).thenReturn("Joshua");
// or..
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return "Joshua";
}
}).when(service).getAuthor();
Note that when using doAnswer, you can't pass a method on when.
// Will throw UnfinishedStubbingException
doAnswer(invocation -> "Joshua").when(service.getAuthor());
So, when would you use doAnswer instead of thenReturn? I can think of two use cases:
When you want to "stub" void method.
Using doAnswer you can do some additionals actions upon method invocation. For example, trigger a callback on queryBookTitle.
BookServiceCallback callback = new BookServiceCallback() {
#Override
public void onSuccess(String bookTitle) {
assertEquals("Effective Java", bookTitle);
}
};
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
BookServiceCallback callback = (BookServiceCallback) invocation.getArguments()[0];
callback.onSuccess("Effective Java");
// return null because queryBookTitle is void
return null;
}
}).when(service).queryBookTitle(callback);
service.queryBookTitle(callback);
When you are using Spy instead of Mock
When using when-thenReturn on Spy Mockito will call real method and then stub your answer. This can cause a problem if you don't want to call real method, like in this sample:
List list = new LinkedList();
List spy = spy(list);
// Will throw java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
when(spy.get(0)).thenReturn("java");
assertEquals("java", spy.get(0));
Using doAnswer we can stub it safely.
List list = new LinkedList();
List spy = spy(list);
doAnswer(invocation -> "java").when(spy).get(0);
assertEquals("java", spy.get(0));
Actually, if you don't want to do additional actions upon method invocation, you can just use doReturn.
List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));
The simplest answer is:
If you need a fixed return value on method call then we should use thenReturn(…)
If you need to perform some operation or the value need to be computed at run time then we should use thenAnswer(…)
I am trying to unit test one of my methods using PowerMock and Mockito and getting NUllPointerException for one of the objects which I have already mocked and defined behavior in my test.
This is the code I am trying to test
protected void setTabList() {
List<ActionBar.Tab> list = TabAdapter.get().getAllEnabledTabs();
listAdapter.setTabList(list);
int itemCount = list.size();
if (itemCount == 1 && list.get(0).equals(TabAdapter.KEYPAD_TAB)) {
header.setVisibility(View.VISIBLE);
listAdapter.hide();
}
}
And this is the test code
#RunWith(PowerMockRunner.class)
#PrepareForTest({Log.class, TabFragment.class, TextView.class, SystemProperties.class})
public class TabFragmentTests extends TestCase {
#Before
public void setUp() {
suppress(method(Log.class, "println_native"));
suppress(everythingDeclaredIn(TextView.class));
suppress(method(SystemProperties.class, "native_get_boolean"));
suppress(method(SystemProperties.class, "native_get", String.class));
tabFragment = new TabFragment();
listAdapter = Mockito.mock(TabList.class);
}
#Test
public void testSetTabList() {
assertNotNull(tabFragment);
assertNotNull(listAdapter);
TabAdapter instance = TabAdapter.get();
TabAdapter spy = spy(instance);
List<ActionBar.Tab> list = new ArrayList<ActionBar.Tab>();
list.add(KEYPAD_TAB);
doAnswer(new Answer<String>() {
#Override
public String answer (InvocationOnMock invocation) {
return "set Tabs";
}
}).when(listAdapter).setTabList(list);
doAnswer(new Answer<String>() {
#Override
public String answer (InvocationOnMock invocation) {
return "hide";
}
}).when(listAdapter).hide();
doReturn(list).when(spy).getAllEnabledTabs();
tabFragment.setTabList();
verify(listAdapter, times(1)).hide();
}
When I run the test and tabFragment.setTabList() is called, listAdapter in setTabList() throws NPE. I am trying to understand why listAdapter.setTabList(list) is not replaced by the "answer" API I have in the test.
I have also tried using Mockito.doNothing().when(listAdapter).setTabList(list) but that doesn't solve the issue.
Another observation is when I create a dummy getTestString(listAdapter) method in my TabFragment class and call it using tabFragment.getTestString(listAdapter) from my test passing mocked listAdapter as an argument, it doesn't through a NPE. Does that mean I have to explicitly pass mocked object to the method call?
You are overriding a method call like this:
when(listAdapter).setTabList(list);
but then you call it like this:
tabFragment.setTabList();
I don't see how that would work. setTabList(list); and setTabList(); call different methods.
I think that you forgot to add "TabAdapter" class to the "PrepareForTest" annotation :
#PrepareForTest({Log.class, TabAdapter.class, TabFragment.class, TextView.class, SystemProperties.class})
My Test
List<Person> myList;
#Test
public void testIsValidPerson() {
myList = new ArrayList<Person>();
myList.add(new Person("Tom"));
when(personDao.get(person)).thenReturn(myList);
when((personDao.get(person)).isEmpty()).thenReturn(false);//------Exception thrown
boolean result = service.isValid("Tom");
assertFalse(result);
}
Method to be tested:
public boolean isValid(String person){
personDao = new PersonDao();
Person personObj = new Person(person);
return (personDao.get(person).isEmpty())?false : true;
}
Exception thrown:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Boolean cannot be returned by get()
get() should return List
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
My Second approach using spy:
public void testIsValidPerson() {
myList = new ArrayList<Person>();
myList.add(new Person("Tom"));
when(personDao.get(person)).thenReturn(myList);
List<Person> mylist = personDao.get(person);
List spy = spy(mylist);
doReturn(false).when(spy.isEmpty());//------exception thrown
boolean result = service.isValid("Tom");
assertFalse(result);
}
This gives me the following exception:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at com.PersonTest.testIsValid(PersonTest.java:76)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
Third appraoch:
#Test
public void testIsValidPerson() {
myList = new ArrayList<Person>();
myList.add(new Person("Tom"));
when(personDao.get(person)).thenReturn(myList);
boolean result = service.isValid("Tom");//--------Throws null pointer exception
assertFalse(result);
}
public boolean isValid(String person){
personDao = new PersonDao();
Person personObj = new Person(person);
return (personDao.get(person).isEmpty())?false : true; //----throws NPE
}
Fourth Approach: throws Null pointer exception
#Test
public void testIsValidPerson() {
List<Person> mockedList = mock(List.class);
when(personDao.get(person)).thenReturn(mockedList);
when(personDao.get(person)).isEmpty().thenReturn(false);
boolean result = service.isValid("Tom");//--------Throws null pointer exception
assertFalse(result);
}
public boolean isValid(String person){
personDao = new PersonDao();
Person personObj = new Person(person);
return (personDao.get(person).isEmpty())?false : true; //----throws NPE
}
Fifth approach: Also gives NPE.
The get method of personDao accesses the database and the NPE is thrown when getting a connection to the DB. But it doesn't give NPE the first time around when I get an empty list back. I get NPE in the second call from service.isValid()
#Test
public void testIsValidPerson() {
when(personDao.get(person)).thenReturn(new ArrayList<Person>());
List tempList=personDao.get(person);//----I get empty tempList---No NPE
boolean result = service.isValid("Tom");//--------Throws null pointer exception
assertFalse(result);
}
Approach 6:
#Test
public void testIsValid() {
personList = new ArrayList<Person>();
Person person = new Person("Tom");
personList.add(person);
when(personDao.get(person)).thenReturn(personList);//-------Uses same person object
boolean result = service.isValid(person);//------------Uses same person object
assertTrue(result);
}
And I changed my method signature from(so that the test and the method under test would use the same value).
public boolean isValid(String name)
to
public boolean isValid(Person person)
Basically you do not have enough mocks.
You are attempting to mock an isEmpty method of a List returned by a mock object. You have a mock object, but you do not make the mock object return a mock list so you could mock the methods of a mock list ...
One thing I fail to understand though is why are you attempting to make a list that has elements, but returns true for isEmpty
If you need to test how your code behaves when it gets an empty list, just make an empty list. This way isEmpty will automatically return false.
when(personDao.get(person)).thenReturn(new ArrayList<Person>());
The line when((personDao.get(person)).isEmpty()).thenReturn(false); makes no sense, because personDao.get(person) isn't a mock. It's just myList, because you stubbed it that way on the line above. So this is exactly the same as doing when(myList.isEmpty()).thenReturn(false); - but you can't stub this because there's no mock here.
To check the number of interactions with a mock where the parameter in the method call is of a certain type, one can do
mock.someMethod(new FirstClass());
mock.someMethod(new OtherClass());
verify(mock, times(1)).someMethod(isA(FirstClass.class));
This will pass thanks to the call to isA since someMethod was called twice but only once with argument FirstClass
However, this pattern seems to not be possible when using an ArgumentCaptor, even if the Captor was created for the particular argument FirstClass
this doesn't work
mock.someMethod(new FirstClass());
mock.someMethod(new OtherClass());
ArgumentCaptor<FirstClass> captor = ArgumentCaptor.forClass(FirstClass.class);
verify(mock, times(1)).someMethod(captor.capture());
it says the mock was called more than once.
Is there any way to accomplish this verification while capturing the argument for further checking?
I recommend using Mockito's Hamcrest integration to write a good, clean matcher for it. That allows you to combine the verification with detailed checking of the passed argument:
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
verify(mock, times(1)).someMethod(argThat(personNamed("Bob")));
Matcher<Person> personNamed(final String name) {
return new TypeSafeMatcher<Person>() {
public boolean matchesSafely(Person item) {
return name.equals(item.getName());
}
public void describeTo(Description description) {
description.appendText("a Person named " + name);
}
};
}
Matchers generally lead to more readable tests and more useful test failure messages. They also tend to be very reusable, and you'll find yourself building up a library of them tailored for testing your project. Finally, you can also use them for normal test assertions using JUnit's Assert.assertThat(), so you get double use out of them.
Quoting the docs:
Note that an ArgumentCaptordon't do any type checks, it is only
there to avoid casting in your code. This might however change (type
checks could be added) in a future major release.
I wouldn't use an ArgumentCaptor for this. This class captures (literally) everything, despite what class was provided as it's .forClass argument.
To achieve what you want I suggest intercept the argument using Mockito's Answer interface:
private FirstClass lastArgument;
#Test
public void captureFirstClass() throws Exception {
doAnswer(captureLastArgument()).when(mock).someMethod(anInstanceOfFirstClass());
mock.someMethod(new FirstClass());
mock.someMethod(new OtherClass());
verify(mock, times(1)).someMethod(anInstanceOfFirstClass());
//write your desired matchers against lastArgument object
}
private Answer<FirstClass> captureLastArgument() {
return new Answer<FirstClass>() {
#Override
public FirstClass answer(InvocationOnMock invocation) throws Throwable {
TestClass.this.lastArgument = (FirstClass) invocation.getArguments()[0];
return null;
}
};
}
private static Object anInstanceOfFirstClass(){
return Mockito.argThat(isA(FirstClass.class));
}
You can use the the captor for the sake of capturing, then verify the number of invocations with each argument type separately.
// given
ArgumentCaptor<AA> captor = ArgumentCaptor.forClass(AA.class);
CC cc = new CC();
// when
cut.someMethod(new AA());
cut.someMethod(new BB());
cut.someMethod(new BB());
cut.someMethod(cc);
// then
Mockito.verify(collaborator, atLeastOnce()).someMethod(captor.capture());
Mockito.verify(collaborator, times(1)).someMethod(isA(AA.class));
Mockito.verify(collaborator, times(2)).someMethod(isA(BB.class));
Mockito.verify(collaborator, times(1)).someMethod(isA(CC.class));
assertEquals(cc, captor.getValue());
Apparently the generic type of the captor reference doesn't affect anything at runtime.
I also encountered this problem today. I thought I could simply do something like
verify(mock).someMethod(and(isA(FirstClass.class), captor.capture()));
but I couldn't get it to work. I ended up with this solution:
#Test
public void Test() throws Exception {
final ArgumentCaptor<FirstClass> captor = ArgumentCaptor.forClass(FirstClass.class);
mock.someMethod(new FirstClass());
mock.someMethod(new OtherClass());
verify(eventBus, atLeastOnce()).post(captor.capture());
final List<FirstClass> capturedValues = typeCheckedValues(captor.getAllValues(), FirstClass.class);
assertThat(capturedValues.size(), is(1));
final FirstClass capturedValue = capturedValues.get(0);
// Do assertions on capturedValue
}
private static <T> List<T> typeCheckedValues(List<T> values, Class<T> clazz) {
final List<T> typeCheckedValues = new ArrayList<>();
for (final T value : values) {
if (clazz.isInstance(value)) {
typeCheckedValues.add(value);
}
}
return typeCheckedValues;
}
Note: if only one class needs to be captured in this way typeCheckedValues can be simplified into:
private static List<FirstClass> typeCheckedValues(List<FirstClass> values) {
final List<FirstClass> typeCheckedValues = new ArrayList<>();
for (final Object value : values) {
if (value instanceof FirstClass) {
typeCheckedValues.add((FirstClass) value);
}
}
return typeCheckedValues;
}
I'm using Mockito and want to do a hopefully simple thing. How do I mock a void method for a particular class? I tried ...
CacheService cs = mock(CacheService.class);
when(cs.startCache()).then( PopulateCache.addTestEntriesToCache() );
But I'm getting the compile error
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:testCompile (default-testCompile) on project cme-productplus-web: Compilation failure: Compilation failure:
[ERROR] \Documents and Settings\E18538\workspace\cme-productplus-web\src\test\java\com\cme\clearing\product\server\PopulateCacheServiceImpl.java:[32,65] 'void' type not allowed here
[ERROR] \Documents and Settings\E18538\workspace\cme-productplus-web\src\test\java\com\cme\clearing\product\server\PopulateCacheServiceImpl.java:[32,20] 'void' type not allowed here
My intention is instead of calling the normal code of CacheService.startCache, I want to call my own method, "PopulateCache.addTestEntriesToCache()". How can I do this?
Edit: Per the response given, I tried editing my class where I implement the mock, but the mock method (the doAnswer, presumably) isn't getting called ...
public class PopulateCacheServiceImpl extends RemoteServiceServlet implements PopulateCacheService {
/**
*
*/
private static final long serialVersionUID = 1L;
public Boolean initCache() {
boolean ret = false;
try {
setupMockCache();
CacheService.getInstance().startCache();
ret = true;
} catch (Exception e) {
e.printStackTrace(System.err);
ret = false;
} // try
return ret;
} // initCache
private void setupMockCache() {
CacheService cs = mock(CacheService.class);
try {
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
PopulateCache.addTestEntriesToCache();
return null;
}
}).when(cs).startCache();
} catch (SQLException e) {
e.printStackTrace();
}
} // setupMockCache
}
Thanks, - Dave
You are making a mock for the CacheService, but you are still not returning it and using it anywhere. Instead, you are calling the real static CacheService.instance() method which will not return your mock. Make you setupMockCache() return the CacheService and use it directly rather than going through the instance() method.
Also in the question title/summary, you said "leave everything else the same". If you mean you want the rest of CacheService to behave the same as it normaly would, then perhaps you want a partial mock, which you can do with Mockito's spy() instead of mock().
Put the call to your cache in the anwser-method of this http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#12
Mockito.doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
PopulateCache.addTestEntriesToCache()
return null;
}
}).when(cs).startCache();
Of course it doesn't work : in setupMockCache you are creating a the cache mock CacheService cs = mock(CacheService.class); on which you define the stub. But the cs instance is never passed.
And in initCache you are calling the setup method, but you don't get the CacheService instance, right after you wrote this statement CacheService.getInstance().startCache(); that will certainly create a real CacheService instance and fo course it won't use the mocked instance.
I don't know what you want to do, this seems weird and wrong to mock partially a Cache in your production code! If I were you I would create my own set of classes that will return your custom cache backed by an inherited CacheService class if necessary (this class will explicitly overide the startCache method).
Hope that helps!