Jmockit и @PostConstruct bean

#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.