Как насмехаться над сервисами с Аркиллиан?
Можно ли использовать какую-то насмешливую фреймворк с Аркиллиан, или точно, как насмехаться с введенными EJB? Я знаю, что с использованием CDI (Contexts and Dependency Injection) можно вводить альтернативы в тест. Но без CDI в качестве механизма впрыска, когда я использую только инъекцию EJB, как это возможно?
Недавно я проверил свои EJB с помощью mock-реализации служебного интерфейса следующим образом:
// Service inteface
public interface Audit {
void audit(String info);
}
// Mock implementation
@Stateless
public class MockAuditBean implements Audit {
public static String lastInfo = null;
@Override
public void audit(String info) {
this.lastInfo = info;
}
}
// assert in test
assertTrue(MockAuditBean.lastInfo.contains("dummy"));
Этот подход возможен, но требует множества пользовательских макетных реализаций. Что еще хуже, инъецированные экземпляры mocks являются прокси-серверами и используют сервисный интерфейс. Их нельзя отбрасывать, чтобы высмеять класс реализации для сравнения результатов. Могут использоваться только статические элементы и методы макетной реализации.
Я также проверил еще одну возможность установки связанных EJB вручную. Этот подход имеет несколько отклонений. Для этого требуется, чтобы целевой EJB теста имел для них не-частные члены или сеттеры. Когда целевой EJB опирается на аннотацию жизненного цикла @PostConstruct, вы должны вызвать его после настройки ручного "инъекции".
Преимуществом этого решения является возможность использования макетных фреймворков, таких как mockito или jMock.
Попросите кого-нибудь поделиться опытом, как тестировать и настраивать такой интеграционный тест, или даже использовать в нем насмешливые фреймворки?
Ответы
Ответ 1
IMO, EJB, которые не предназначены для тестирования. Ваша альтернатива звучит как довольно хороший компромисс, и я бы пошел на это. Использование mockito является основным плюсом, и я использую его даже при работе с CDI.
Я бы использовал область полномочий по умолчанию, а javadoc для других разработчиков обращался к ним только для целей тестирования.
Ответ 2
В этой статье из Oracle показан подход к "инъекции" EJB для тестирования с использованием JUnit и Mockito:
http://www.oracle.com/technetwork/articles/java/unittesting-455385.html
Изменить:
В принципе, включение Mockito позволяет издеваться над такими объектами, как EntityManager и т.д.:
import static org.mockito.Mockito.*;
...
em = mock(EntityManager.class);
Они показывают подход для EJB, также используя mockito. Учитывая EJB:
@Stateless
public class MyResource {
@Inject
Instance<Consultant> company;
@Inject
Event<Result> eventListener;
Тест может "вводить" те объекты:
public class MyResourceTest {
private MyResource myr;
@Before
public void initializeDependencies(){
this.myr = new MyResource();
this.myr.company = mock(Instance.class);
this.myr.eventListener = mock(Event.class);
}
Обратите внимание, что MyResource и MyResource находятся в том же пути класса, но в разных исходных папках, поэтому ваши тесты имеют доступ к защищенным полям, company
и eventListener
.
Edit:
Примечание: вы можете использовать FacesMockitoRunner
из JBoss (https://community.jboss.org/thread/170800), чтобы сделать это для общих компонентов JSF и использовать аннотации для другие (Java EE 6 с CDI включен в качестве предварительного условия для этого, но не требует сервера JBoss):
-
Включить зависимости jsf, mockito и jsf-mockito в maven:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.test-jsf</groupId>
<artifactId>jsf-mockito</artifactId>
<version>1.1.7-SNAPSHOT</version>
<scope>test</scope>
</dependency>
-
Добавьте аннотацию @RunWith
к вашему тесту:
@RunWith(FacesMockitoRunner.class)
public class MyTest {
-
Вложение общих объектов Faces с помощью аннотаций:
@Inject
FacesContext facesContext;
@Inject
ExternalContext ext;
@Inject
HttpServletRequest request;
-
Отметьте любые другие объекты с помощью аннотаций @org.mockito.Mock
(он появляется FacesMockitoRunner
вызывает это за кулисами, поэтому здесь может быть не нужно):
@Mock MyUserService userService;
@Mock MyFacesBroker broker;
@Mock MyUser user;
-
Запустите Injected Mocks с помощью
@Before public void initMocks() {
// Init the mocks from above
MockitoAnnotations.initMocks(this);
}
-
Установите свой тест как обычно:
assertSame(FacesContext.getCurrentInstance(), facesContext);
when(ext.getSessionMap()).thenReturn(session);
assertSame(FacesContext.getCurrentInstance().getExternalContext(), ext);
assertSame(FacesContext.getCurrentInstance().getExternalContext().getSessionMap(), ext.getSessionMap());
и др.
Ответ 3
Вы можете взглянуть на testfun-JEE, который позволяет вам тестировать (не интегрировать-тест) ваши EJB за пределами контейнер.
testfun-JEE заботится о том, чтобы вводить EJB, а также EntityManager и некоторый стандартный ресурс непосредственно в ваш тестовый класс - ссылки в этих EJB на другие EJB разрешаются автоматически.
И самое крутое, что вы можете издеваться над любой зависимостью, просто добавив переменную-член к вашему тесту, аннотированную с помощью @Mock
- testfun-JEE будет вводить этот макет, где нужно.
См. примеры в https://github.com/michaelyaakoby/testfun.
BTW, в то время как эта структура была опубликована совсем недавно (например, сегодня...), она широко используется более года в моей компании.
Ответ 4
Если вы действительно хотите взаимодействовать с mocks в своих тестах интеграции (например, одна из причин может заключаться в том, что вы еще не выполняете полномасштабную реализацию или у вас есть внешний вид внешних систем, в которых у вас нет контроля), существует довольно простой способ интегрировать Mockito с вашими испытаниями Arquillian, посмотрите этот пример из витрины. Он фактически расширяет сам по себе, но не выпускается как один.
Ответ 5
Работайте с каркасом, например, Mockito.
К сожалению, Arquillian автоматически не включает необходимые зависимости.
Вы можете добавить их в свою функцию @Deployment
:
@Deployment
public static WebArchive deploy()
{
return ShrinkWrap.create(WebArchive.class)
.addAsLibraries( // add maven resolve artifacts to the deployment
DependencyResolvers.use(MavenDependencyResolver.class)
.artifact("org.mockito:mockito-all:1.8.3")
.resolveAs(GenericArchive.class))
);
}
источник
Затем в вашем методе @Test
вы можете использовать:
mock(MockedService.class).methodName()
Эта демонстрация github показывает способ автоматического обнаружения, который, как представляется, требует некоторой настройки:
источник