Есть ли способ заменить динамические методы? - PullRequest
1 голос
/ 29 марта 2011

Допустим, у нас есть интерфейс, который имеет два метода:

public interface MyInterface {
    public SomeType first();
    public SomeType second();
}

Этот интерфейс реализован MyInterfaceImpl. Внутри реализации first() вызывает second() для получения некоторых результатов.

Я хочу построить модульный тест, который бы утверждал, что вещи из first() основаны на том, что выходит из second(), подобно:

1  public class MyInterfaceTest {
2     private MyInterface impl = new MyInterfaceImpl();

4     @Test
5     public void testFirst() {
6         // modify behaviour of .second()
7         impl.first();
8         assertSomething(...);

10        // modify behaviour of .second()
11        impl.first();
12        assertSomethingElse(...);
13    }
14 }

Существует ли простой способ создать макет в строке 2, чтобы все вызовы выбранных методов (например, first()) были бы вызваны напрямую (делегированы MyInterfaceImpl), тогда как некоторые другие методы (например, * 1017) *) заменены на макетные аналоги?

Это на самом деле очень легко сделать с PowerMock для статических методов, но мне нужно нечто подобное для динамических.

Решения на основе

MyInterface mock = EasyMock.createMock(MyInterface.class);
MyInterface real = new MyInterfaceImpl();
EasyMock.expect(mock.first()).andReturn(real.first()).anyTimes();
EasyMock.expect(mock.second()).andReturn(_somethingCustom_).anyTimes();

не достаточно хороши, особенно для интерфейсов, имеющих много методов (много шаблонов). Мне нужно поведение переадресации, поскольку real на самом деле зависит от других макетов.

Я ожидаю, что что-то подобное будет обрабатываться фреймворком, а не моим собственным классом. Это достижимо?

Ответы [ 3 ]

2 голосов
/ 29 марта 2011

Похоже, у вас вполне могут быть отдельные интерфейсы для first() и second(), если реализация first() должна вызывать second(). Затем вы можете разделить реализацию и макетировать second() во время тестирования first(). Без более конкретного примера того, что такое first() и second(), сложно сказать наверняка.

Использование EasyMock в классе реализации для макетирования только second() вызов может работать, но, похоже, вы все равно этого не хотите. может потребовать, чтобы EasyMock передавал вызовы first() через обычную реализацию - я не уверен.

Другой вариант может заключаться в создании подкласса реализации в тестовом классе (как вложенный класс), что позволяет вам переопределить только second() для целей тестирования. Хотя это довольно уродливо.

Лично мне не нравится подделывать часть класса, чтобы проверить остальные. Я бы предпочел подделать все зависимости класса.

1 голос
/ 29 марта 2011

Как насчет старого доброго подкласса?Я имею в виду что-то вроде

private MyInterface impl = new MyInterfaceImpl(){
    public final MyInterface mock = EasyMock.createMock(MyInterface.class);
    @override //only the method you need to mock
    public SomeType second(){
        return mock.second();        
    }
}

@Test
public void testFirst() {
    // modify behaviour of .second()
    EasyMock.expect(impl.mock.second()).andReturn("What I want").anyTimes();
    impl.first();
    assertSomething(...);

    // modify behaviour of .second()
    EasyMock.expect(impl.mock.second()).andReturn("Now I want something else").anyTimes();
    impl.first();
    assertSomethingElse(...);
}

Вы тестируете не тот класс, который хотите протестировать, а анонимный подкласс.Но мы можем предположить, что подклассы хорошо работают в Java.; -)

1 голос
/ 29 марта 2011

Возможно, вы могли бы использовать Динамический прокси .

...