mockito: Is there a way of capturing the return value of stubbed method?

As an alternative to @JeffFairley's answer, you can leverage AtomicReference<T>. It will act as a Holder<T>, but I prefer this over real holders because it's defined in Java's base framework.

// 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()
AtomicReference<QueryResult> reference = new AtomicReference<>();
doAnswer(invocation -> {
    QueryResult result = (QueryResult)invocation.callRealMethod();
    reference.set(result);
    return result;
}).when(spiedDao).find(any(User.class), any(Query.class));

// execute once
service.run();
assertThat(reference.get()).isEqualTo(/* something */);

/// change conditions ///

// execute again
service.run();
assertThat(result.get()).isEqualTo(/* something different */);

In my opinion: ResultCaptor is cool stuff that may be integrated in Mockito in the future, is widely reusable and short in syntax. But if you need that sporadically, then few lines of a lambda can be more concise


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])
     }

 });

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 */);

Tags:

Java

Mockito