Имитирующее внедрение EJB в тесты

#java #junit #ejb #easymock

#java #junit #ejb #easymock

Вопрос:

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

 public class A {

    @EJB
    B b;

    // Used in tests to inject EJB mock
    protected A(B b) {
        this.b = b;
    }

    public A() {}

    // Method that I wish to test
    public void foo() {
        b.bar();
    }

}
  

Есть ли другой способ имитировать внедрение ресурсов или это правильный шаблон, которому нужно следовать?

Ответ №1:

вы могли бы использовать для этого easy gloss, это имитирует систему внедрения EJBs.

другой способ — установить поле с использованием отражения в ваших тестах, я иногда использую что-то вроде этого :

 public static void setPrivateField(Class<? extends Object> instanceFieldClass, Object instance, String fieldName, Object fieldValue) throws Exception {
    Field setId = instanceFieldClass.getDeclaredField(fieldName);
    setId.setAccessible(true);
    setId.set(instance, fieldValue);
}
  

Комментарии:

1. Что-то вроде easy gloss было тем, что я искал, спасибо!

2. Использование отражения проблематично, поскольку ссылка на EJB на самом деле является ссылкой на объект-заглушку в контейнере EJB (указывающий на EJB), вы не можете проверить сам фактический EJB.

Ответ №2:

Eliocs,

Если ввести B где интерфейс, то вы бы не «просто» делали это для тестовых случаев; вы бы допускали любые альтернативные реализации «поведения B», даже если необходимость в нем / них еще не была придумана.

Да, в принципе, это единственный шаблон, которому нужно следовать (AFAIK)… так что (правильно или неправильно) вы также можете извлечь из этого максимум пользы 😉

Приветствия. Кит.

Ответ №3:

Это, безусловно, один из способов сделать это, хотя я бы полагался на доступ к пакету; не указывайте точку внедрения конструктора, а просто разместите свой тест в том же пакете, что и тестируемый компонент. Таким образом, ваш тест может просто получить доступ к значению напрямую (при условии, что оно не является закрытым):

 @Test
public void EJBInjectionTest() {
   A a=new A();
   a.b=new B() {
       // mock functionality here, of course...
   };
   assertNotNull(a.b);
}
  

Комментарии:

1. Мне нравится этот способ, потому что нет необходимости добавлять дополнительные строки кода. Спасибо!

2. ПРИВЕТ .. возможно ли это, если B — это интерфейс. пожалуйста, предложите также, как мы можем имитировать объект

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

Ответ №4:

Согласно этой статье (Mockito и внедрение зависимостей), Mockito поддерживает внедрение издевательских ресурсов.

 public class ATest
{
    @InjectMocks
    private A a; //this is your class under test into which the mocks will be injected.

    @Mock
    private B b; //this is the EJB to be injected.

    @Before
    public void setUp()
    {
        MockitoAnnotations.initMocks(this);
    }

}
  

Вы также можете внедрить несколько макетов. Просто объявите их таким же образом, как мы сделали для B b.
Часть initMocks также может быть выполнена в каждом тесте или в методе настройки BeforeClass в зависимости от ваших потребностей.

Комментарии:

1. В статье упоминаются только аннотации Spring Autowired и JSR330 для внедрения. В нем не упоминается аннотация EJB, которая является именно тем, о чем спрашивали. Я только что протестировал эту настройку с Mockito v3.11.1, и неудивительно, что она НЕ работает. В любом случае сопротивлялся желанию понизить голос.