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

前端 未结 3 1217
旧时难觅i
旧时难觅i 2021-02-12 12:51

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())).thenAnswe         


        
相关标签:
3条回答
  • 2021-02-12 13:29

    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

    0 讨论(0)
  • 2021-02-12 13:34

    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])
         }
    
     });
    
    0 讨论(0)
  • 2021-02-12 13:47

    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 */);
    
    0 讨论(0)
提交回复
热议问题