#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, и неудивительно, что она НЕ работает. В любом случае сопротивлялся желанию понизить голос.