If I mock a method to return a new instance of some object, how can I capture the returned instance?
E.g.:
when(mock.someMethod(anyString())).thenAnswer(new Answer() { Object answer(InvocationOnMock invocation) { Object[] args = invocation.getArguments(); Object mock = invocation.getMock(); return new Foo(args[0]) } });
Obviously, I can have a field of type Foo and inside answer
set it to the new instance, but is there a nicer way? Something like ArgumentCaptor?
You can return values from mocked methods by using the returnValue action within the " will " clause of an expectation. oneOf (calculator). add(2, 2); will(returnValue(5)); jMock will fail the test if you try to return a value of the wrong type.
A stub is a fake class that comes with preprogrammed return values. It's injected into the class under test to give you absolute control over what's being tested as input. A typical stub is a database connection that allows you to mimic any scenario without having a real database.
In Mockito, you can specify what to return when a method is called. That makes unit testing easier because you don't have to change existing classes. Mockito supports two ways to do it: when-thenReturn and doReturn-when . In most cases, when-thenReturn is used and has better readability.
I wanted to do something similar, but with a spied object rather than a mock. Specifically, given a spied object, I want to capture the return value. Based on Andreas_D's answer, here's what I came up with.
public class ResultCaptor<T> implements Answer { private T result = null; public T getResult() { return result; } @Override public T answer(InvocationOnMock invocationOnMock) throws Throwable { result = (T) invocationOnMock.callRealMethod(); return result; } }
Intended usage:
// spy our dao final Dao spiedDao = spy(dao); // instantiate a service that does some stuff, including a database find final Service service = new Service(spiedDao); // let's capture the return values from spiedDao.find() final ResultCaptor<QueryResult> resultCaptor = new ResultCaptor<>(); doAnswer(resultCaptor).when(spiedDao).find(any(User.class), any(Query.class)); // execute once service.run(); assertThat(resultCaptor.getResult()).isEqualTo(/* something */); /// change conditions /// // execute again service.run(); assertThat(resultCaptor.getResult()).isEqualTo(/* something different */);
Looks like you want to observe and then Answer
instances, and receive notifications each time the answer
method is called (which triggers the creation of a new Foo
). So why not invent an ObservableAnswer
class:
public abstract class ObservableAnswer implements Answer { private Listener[] listeners; // to keep it very simple... public ObservableAnswer(Listener...listeners) { this.listeners = listeners; } @Override public Object answer(InvocationOnMock invocation) { Object answer = observedAnswer(invocation); for (Listener listener:listeners) { listener.send(answer); } return answer; } // we'll have to implement this method now public abstract Object observedAnswer(InvocationOnMock invocation); }
Intended use:
Listener[] myListeners = getListeners(); // some magic (as usual) when(mock.someMethod(anyString())).thenAnswer(new ObservableAnswer(myListeners) { Object observedAnswer(InvocationOnMock invocation) { Object[] args = invocation.getArguments(); Object mock = invocation.getMock(); return new Foo(args[0]) } });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With