Mockito + Spy: как собрать возвращаемые значения

У меня есть класс, использующий фабрику для создания некоторого объекта. В моем модульном тесте я хотел бы получить доступ к возвращаемому значению factory. Поскольку фабрика напрямую передается классу, а геттер для созданного объекта не предоставляется, мне нужно перехватить возврат объекта из фабрики.

RealFactory factory     = new RealFactory();
RealFactory spy         = spy(factory);
TestedClass testedClass = new TestedClass(factory);

// At this point I would like to get a reference to the object created
// and returned by the factory.

Есть ли возможность получить доступ к возвращаемому значению фабрики? Вероятно, с помощью шпиона?
Единственный способ, который я вижу, это имитировать фабричный метод создания.


person Marc-Christian Schulze    schedule 17.08.2011    source источник
comment
Почему TestedClass должен принимать фабрику в качестве зависимости. Разве он не должен просто запрашивать фактический класс, созданный фабрикой. ?(Закон Деметры)   -  person Ajay George    schedule 17.08.2011
comment
TestedClass является компонентом OSGi. Метод компонента требует при каждом вызове нового объекта, созданного фабрикой. Я преобразовал создание объекта в фабричный класс, чтобы обеспечить лучшую тестируемость. Поскольку созданный объект инициализируется в зависимости от параметров метода, нет возможности просто передать созданные объекты вместо фабрики.   -  person Marc-Christian Schulze    schedule 17.08.2011


Ответы (2)


Прежде всего, вы должны передать spy в качестве аргумента конструктора.

Кроме того, вот как вы могли бы это сделать.

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;
    }
}

Предполагаемое использование:

RealFactory factory     = new RealFactory();
RealFactory spy         = spy(factory);
TestedClass testedClass = new TestedClass(spy);

// At this point I would like to get a reference to the object created
// and returned by the factory.


// let's capture the return values from spy.create()
ResultCaptor<RealThing> resultCaptor = new ResultCaptor<>();
doAnswer(resultCaptor).when(spy).create();

// do something that will trigger a call to the factory
testedClass.doSomething();

// validate the return object
assertThat(resultCaptor.getResult())
        .isNotNull()
        .isInstanceOf(RealThing.class);
person Jeff Fairley    schedule 05.09.2014
comment
Спасибо, что поделился. ИМХО: это должен быть принятый ответ. - person BetaRide; 01.12.2016
comment
Возвращает ли это копию результата или тот же экземпляр? - person nahzor; 13.02.2019
comment
он вернет тот же экземпляр - person Jeff Fairley; 15.02.2019
comment
Спасибо Джефф, это было действительно полезно - person timon_the_destroyer; 31.03.2020
comment
Это похоже на то, что я ожидаю от Mockito. Это работает, но, может быть, это плохой дизайн, если нам нужно тестировать вот так? spy() doc намекнул мне в этом направлении. У кого-нибудь есть идеи? - person Ev0oD; 25.11.2020

Стандартный насмешливый подход будет заключаться в следующем:

  1. Предварительно создайте объект, который вы хотите, чтобы фабрика вернула в тестовом примере.
  2. Создать макет (или шпион) фабрики
  3. Прописать mock factory, чтобы он возвращал ваш предварительно созданный объект.

Если вы действительно хотите, чтобы RealFactory создавал объект на лету, вы можете подклассировать его и переопределить фабричный метод для вызова super.create(...), затем сохранить ссылку на поле, доступное тестовому классу, и затем вернуть созданный объект.

person oksayt    schedule 17.08.2011