#java #jakarta-ee #jmockit #postconstruct
#java #джакарта-ee #jmockit #постконструкция
Вопрос:
Я создал компонент с методом, который хочу протестировать. К сожалению, это компонент с аннотацией PostConstruct в нем. Я не хочу вызывать метод PostConstruct. Как я могу это сделать?
Я пробовал 2 разных способа (как показано в примере ниже), но ни один из них не работает; init() все равно вызывается.
Может кто-нибудь, пожалуйста, дать мне подробный пример того, как это сделать?
DirBean.java
@Singleton
@Startup
public class DirBean implements TimedObject {
@Resource
protected TimerService timer;
@PostConstruct
public void init() {
// some code I don't want to run
}
public void methodIwantToTest() {
// test this code
}
}
MyBeanTest.java
public class MyBeanTest {
@Tested
DirBean tested;
@Before
public void recordExpectationsForPostConstruct() {
new Expectations(tested) {
{
invoke(tested, "init");
}
};
}
@Test
public void testMyDirBeanCall() {
new MockUp<DirBean>() {
@Mock
void init() {
}
};
tested.methodIwantToTest();
}
}
MyBeanTest2.java (РАБОТАЕТ)
public class MyBeanTest2 {
@Tested
DirBean tested;
@Before
public void recordExpectationsForPostConstruct() {
new MockUp<DirBean>() {
@Mock
void init() {}
};
}
@Test
public void testMyDirBeanCall() {
tested.methodIwantToTest();
}
}
MyBeanTest3.java (РАБОТАЕТ)
public class MyBeanTest3 {
DirBean dirBean = null;
@Mock
SubBean1 mockSubBean1;
@Before
public void setupDependenciesManually() {
dirBean = new DirBean();
dirBean.subBean1 = mockSubBean1;
}
@Test
public void testMyDirBeanCall() {
dirBean.methodIwantToTest();
}
}
MyBeanTest4.java (СБОЙ с NullPointerException при вызове())
public class MyBeanTest4 {
@Tested
DirBean tested;
@Before
public void recordExpectationsForCallsInsideInit() {
new Expectations(tested) {
{
Deencapsulation.invoke(tested, "methodCalledfromInit", anyInt);
}
};
}
@Test
public void testMyDirBeanCall() {
tested.methodIwantToTest();
}
}
Комментарии:
1. Я думаю, вы делаете это неправильно.
init()
Метод является неотъемлемой частью тестируемого класса, над ним не следует издеваться. Вместо этого издевайтесь над любым другим компонентом, который он вызывает, если это необходимо.2. Возможно, но проблема в том, что init() вызывается перед тестированием. Поэтому, если я попытаюсь воспроизвести частные вызовы, выполненные внутри init() , это выдаст мне исключение с нулевым указателем для тестируемой переменной. Может быть, я не могу использовать @Tested в этом случае?
3. Если
init()
вызывает другие методы в том же тестируемом классе (private
или нет), их также не следует высмеивать. Единственными методами, которые «следует» использовать, являются методы, принадлежащие классам, отличным от тестируемого. Было бы легче помочь, если бы я знал, в чем заключается реальная проблема .4. Функция инициализации создает таймер, который будет ждать x минут, а затем вызовет другую функцию и, наконец, создаст новый таймер. Поэтому его запуск не был бы полезен в модульном тестировании, и поэтому вы хотите полностью его высмеять. Надеюсь, я объяснил это достаточно хорошо .. 😉
5. Тест должен иметь
@Injectable TimerService timer
, в противном@Tested DirBean
случае сбой (поскольку@Resource
указывает на обязательную зависимость). Итак, предполагая, что таймер создается сinit()
помощью макетаtimer
, в чем проблема?
Ответ №1:
Переместить определение типа макета в метод @Before:
public class MyBeanTest {
@Tested
DirBean tested;
@Before
public void recordExpectationsForPostConstruct() {
new MockUp<DirBean>() {
@Mock
void init() {
}
};
}
@Test
public void testMyDirBeanCall() {
tested.methodIwantToTest();
}
}
Комментарии:
1. Спасибо за ответ. Это сработало, но получило предупреждение: Предупреждение: недопустимый макет для внутреннего класса DirBean на MyBeanTest$ 1.<инициализация> (MyBeanTest.java ). Тем не менее, это сработало. Похоже, это недавно добавленное предупреждение. Другой способ сделать это был: инициализировать DirBean как обычную переменную (без @Tested ) и добавить, а затем инициализировать введенные компоненты вручную. Например:
2. ‘@Before public void BeforeTest() { dirBean = new DirBean(); dirBean.subBean = mockSubBean; и т.д. и т.п.}’
3. Хм, я не вижу этого предупреждения, я использую версию 1.25 JMockit.