EasyMock: недействительные методы

У меня есть метод, который возвращает void в классе, который является зависимостью класса, который я хочу проверить.

Этот класс огромен, и я использую только этот единственный метод. Мне нужно заменить реализацию этого метода для теста, поскольку я хочу, чтобы он делал что-то другое, и мне нужно иметь доступ к параметрам, которые получает этот метод.

Я не могу найти способ сделать это в EasyMock. Я думаю, что я знаю, как это сделать с помощью Mockito с помощью doAnswer, но я не хочу добавлять другую библиотеку, если это абсолютно необходимо.

Ответ 1

Если я понимаю, что вы хотите сделать правильно, вы должны использовать andAnswer():

mockObject.someMethod(eq(param1), eq(param2));
expectLastCall().andAnswer(new IAnswer() {
    public Object answer() {
        //supply your mock implementation here...
        SomeClass arg1 = (SomeClass) getCurrentArguments()[0];
        AnotherClass arg2 = (AnotherClass) getCurrentArguments()[1];
        arg1.doSomething(blah);
        //return the value to be returned by the method (null for void)
        return null;
    }
});

Руководство пользователя EasyMock объясняет:

Создание возвращаемых значений или исключений

Иногда мы хотели бы, чтобы наш mock-объект возвращал значение или генерировал исключение, созданное во время фактического вызова. Начиная с EasyMock 2.2, объект возвращается expectLastCall() и expect(T value) предоставляет метод andAnswer(IAnswer answer), который позволяет [вам] указать реализацию интерфейса IAnswer, который используется для создания возвращаемого значения или исключения.

Внутри обратного вызова IAnswer аргументы, переданные макету вызова, доступны через EasyMock.getCurrentArguments(). Если вы их используете, рефакторинг, такой как параметры переупорядочения, может нарушить ваши тесты. Вы были предупреждены.

Ответ 2

Если вы просто вызываете метод void для каждого раза, когда вы ожидаете его вызова, а затем вызываете EasyMock.expectLastCall() до вызова replay(), Easymock будет "помнить" каждый вызов.

Поэтому я не думаю, что вам нужно явно называть expect() (кроме lastCall), поскольку вы не ожидаете ничего из метода void, кроме его вызова.

Спасибо Крису!

"Fun With EasyMock" от пользователя StackOverflow Burt Beckwith - это хорошее сообщение в блоге, которое обеспечивает более подробную информацию. Заметная выдержка:

В основном поток, который я обычно использую:

  • Создайте макет
  • вызов expect(mock.[method call]).andReturn([result]) для каждого ожидаемого вызова
  • вызов mock.[method call], затем EasyMock.expectLastCall() для каждого ожидаемого недействительного вызова
  • вызов replay(mock) для перехода из режима записи в режим воспроизведения.
  • вводить макет при необходимости
  • вызов метода проверки
  • вызов verify(mock), чтобы убедиться, что все ожидаемые вызовы произошли

Ответ 3

Если вы хотите получить доступ к параметрам позже, вы также можете оценить класс Captures, который является новым для EasyMock 2.4.

Вместо помощника вы можете использовать экземпляр класса "Capture". Когда вызывается метод издевательства, экземпляр Capture будет хранить параметр, с которым он был вызван.

Capture<ChartPanel> captured = new Capture<ChartPanel>();
// setChartPanel is going to be called during execution;
// we want to verify some things about the ChartPanel
// instance it invoked with
chartMock.setChartPanel(capture(captured));
replay(chartMock);

ufdm.setChartAnnotater(chartMock);
// afterPropertiesSet triggers the setChartPanel call...
ufdm.afterPropertiesSet();
verify(chartMock);

// verify some things about the ChartPanel parameter our
// mock object was invoked with
assertSame(plot, captured.getValue().getChart().getPlot());

Ответ 4

Возможно, вы захотите проверить PowerMock. EasyMock основан на API-интерфейсе прокси-отражения, означающем, что все является прокси-сервером, и вы можете тестировать только интерфейсы и, следовательно, только не конечные методы и классы. Это может сработать для некоторых, но если вы тестируете мир как построенный, вам потребуется больше энергии.

В PowerMock API-интерфейс инструментария Java 5 устраняет ограничения. Не нужно записывать реализацию имитационного объекта тестируемого объекта (просто уродливое ИМО). Пара PowerMock с Mockito (или JMockit), и вы действительно будете в гонке.

Конечно, есть другое направление переписывания вашего кода, которое будет легче тестироваться, что также является хорошей идеей, если это возможно.

Ответ 5

В таких ситуациях я обнаружил, что создание вложенного класса в классе unit test и переопределение методов со специальными требованиями таким образом - лучший маршрут. Поэтому, если вы тестируете ClassA который имеет этот метод с параметрами, которые вам нужны для доступа, вы бы сделали что-то вроде:

class MockClassA extends ClassA {
    @Override
    void specialMethod(String param1, String param2) {
        // do logging or manipulation of some sort
        super.specialMethod(param1,param2); // if you need to
    }
}

В моем модульном модуле тестирования я просто использую этот экземпляр вместо этого. Просто относитесь к нему так, как если бы это был какой-то другой макет. Гораздо проще, чем смешивать библиотеки, которые я согласен, вероятно, не очень хорошая идея.