PowerMockito: как издеваться над методами, вызываемыми конструктором?

У меня есть следующий класс:

public class Foo {

  public Foo() {
     initField1();
     initField2();
     initField3();
  }

}

Мне нужно изменить поведение (издеваться) initField1() и initField3(), чтобы они ничего не делали или что-то еще, что они на самом деле делают. Меня интересует выполнение фактического кода initField2().

Я хочу написать следующий тест:

Foo foo = new Foo();
assertTrue(foo.myGet());

myGet() возвращает атрибут Foo, вычисленный initField2().

Методы initField(), конечно же, являются частными.

Как я могу сделать такое?

Спасибо за вашу помощь и с наилучшими пожеланиями.


person Julien Collah    schedule 06.05.2013    source источник


Ответы (2)


Учитывая, что в устаревшем коде может произойти что угодно :), вы можете использовать PowerMock для подавления методов, как описано в http://code.google.com/p/powermock/wiki/SuppressUnwantedBehavior

import static org.powermock.api.support.membermodification.MemberMatcher.methods;
import static org.powermock.api.support.membermodification.MemberModifier.suppress;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Foo.class)
public class FooTest {

    @Test
    public void testSuppressMethod() throws Exception {
        suppress(methods(Foo.class, "initField1", "initField3"));
        Foo foo = new Foo();
    }
}

Тем не менее, вам следует провести рефакторинг класса после того, как вы получите для него адекватное тестовое покрытие.

person denis.solonenko    schedule 07.05.2013
comment
Большое спасибо. Теперь это работает! Еще один вопрос, как мне проверить, что initField2() был вызван? Я думал о том, чтобы подсмотреть мой новый Foo, но на самом деле с ним нет никакого взаимодействия, поэтому verifyPrivate(foo).invoke(initField2) не помогает. - person Julien Collah; 07.05.2013
comment
@JulienCollah вы проверите это косвенно, проверив, что foo.myGet() возвращает правильное значение. - person denis.solonenko; 08.05.2013

Я думаю, что что-то не так в том, что вы хотите сделать.

Насколько я понимаю, мокационная среда, такая как Mockito или PowerMock, предназначена для имитации взаимодействия между тестируемым объектом и его зависимостями.

Насколько я понимаю ваш вопрос, вы хотите смоделировать часть поведения объекта и протестировать остальную часть.

В вашем случае вы хотите проверить то, что никогда не произойдет, так как initField2() никогда не будет вызываться без вызовов initField1() и initField3()

Если причина, по которой вы не хотите вызывать initField1() и initField3, заключается в том, что эти методы взаимодействуют с другими объектами, файловой системой или БД, то вам лучше вводить зависимости через аргумент конструктора или аннотированные сеттеры и просто вводить макеты для ваших тестов. А чтобы создать экземпляр объекта с правильно настроенными зависимостями, используйте фабричный шаблон, шаблон построителя или, что еще лучше, используйте инфраструктуру внедрения зависимостей, такую ​​как Spring или Google Guice.

Если причина, по которой вы не хотите вызывать initField1() и initField3, заключается в том, что они имеют дело с разной бизнес-логикой в ​​вашем объекте, то это пахнет (как в http://martinfowler.com/books/refactoring.html), как будто вы нарушаете принцип единой ответственности и должны провести рефакторинг.

person rcomblen    schedule 06.05.2013
comment
Это унаследованный код. Я предпочитаю не изменять тестируемый класс, например, создавая новый конструктор, принимающий аргументы. Я хочу, чтобы выполнялось только initField2(), потому что оно отвечает за настройку поля, которое я хочу протестировать. Мне не интересно тестировать остальную логику конструктора. - person Julien Collah; 07.05.2013
comment
Mockito предназначен для имитации взаимодействия, PowerMock предназначен для имитации частичной внутренней работы класса для устаревшего кода, поэтому этот ответ просто неверен. - person eis; 26.11.2013