Как издеваться над сервисами с Arquillian? - PullRequest
15 голосов
/ 28 февраля 2011

Можно ли использовать Arquillian какой-то фальшивый фреймворк, или точно, как имитировать инжектированные EJB?Я знаю, что с использованием CDI (внедрение контекстов и зависимостей) можно вводить альтернативы в тесте.Но без CDI в качестве механизма внедрения, когда я использую только EJB-инъекцию, как это возможно?

Недавно я протестировал свои EJB-компоненты с фиктивной реализацией интерфейса сервиса следующим образом:

// 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"));

Такой подход возможен, но требует большого количества пользовательских макетов.Что еще хуже, внедренные экземпляры макетов являются прокси и используют сервисный интерфейс.Их нельзя привести к макету класса реализации для сравнения результатов.Можно использовать только статические члены и методы фиктивной реализации.

Я проверил и другие возможности для установки связанных EJB-компонентов вручную.Этот подход имеет несколько недостатков.Это требует, чтобы у целевого EJB теста были не частные члены или сеттеры для них.Когда целевой EJB полагается на аннотацию жизненного цикла @PostConstruct, вы должны вызывать ее после ручной настройки «инъекции».Преимуществом этого решения является возможность использовать фиктивные фреймворки, такие как mockito или jMock.

У кого-нибудь есть опыт, которым можно поделиться, как протестировать и настроить такой интеграционный тест, или даже использовать в нем фальшивые фреймворки?

Ответы [ 5 ]

3 голосов
/ 17 мая 2011

IMO, EJB, где не предназначены для тестирования.Ваша альтернатива звучит как достаточно хороший компромисс, и я бы пошел на это.Использование mockito является основным плюсом, и я использую его даже при работе с CDI.

Я бы использовал область элементов «default» и javadoc, чтобы другие разработчики обращались к ним только для целей тестирования.

2 голосов
/ 02 ноября 2013

Возможно, вы захотите взглянуть на testfun-JEE , который позволяет вам тестировать (а не интегрировать) свои EJB-компоненты вне контейнера.testfun-JEE заботится о внедрении EJB-компонентов, а также EntityManager и некоторых стандартных ресурсов непосредственно в ваш тестовый класс - ссылки в этих EJB-компонентах на другие EJB-компоненты разрешаются автоматически.

И самое крутое, что вы можете высмеивать любую зависимостьпросто добавив переменную-член в ваш тест, помеченный @Mock - testfun-JEE внедрит этот макет везде, где это необходимо.

См. примеры в https://github.com/michaelyaakoby/testfun.

BTW, пока эта структура была опубликованасовсем недавно (как сегодня ...) он широко используется в моей компании более года.

2 голосов
/ 25 января 2013

В этой статье от 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.


Редактировать:

Примечание: вы можете использовать FacesMockitoRunner из JBoss (https://community.jboss.org/thread/170800), чтобы получитьэто сделано для общих компонентов JSF и использования аннотаций для других (Java EE 6 с CDI включен в качестве предварительного условия для этого, но не требует сервера JBoss):

  1. Включить 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>
    
  2. Добавьте аннотацию @RunWith в свой тест:

    @RunWith(FacesMockitoRunner.class)
    public class MyTest {
    
  3. Внедрение общих объектов Faces с использованием аннотаций:

    @Inject
    FacesContext facesContext;
    @Inject
    ExternalContext ext;
    @Inject
    HttpServletRequest request;
    
  4. Копирование любых других объектов с использованием аннотаций @org.mockito.Mock (кажется, FacesMockitoRunner вызывает это за кулисами, поэтому в этом нет необходимостиздесь):

    @Mock MyUserService userService;
    @Mock MyFacesBroker broker;
    @Mock MyUser user;
    
  5. Инициируйте введенные макеты с помощью

    @Before public void initMocks() {
        // Init the mocks from above
        MockitoAnnotations.initMocks(this);
    }
    
  6. Настройте свой тест как обычно:

    assertSame(FacesContext.getCurrentInstance(), facesContext);
    when(ext.getSessionMap()).thenReturn(session);
    assertSame(FacesContext.getCurrentInstance().getExternalContext(), ext);
    assertSame(FacesContext.getCurrentInstance().getExternalContext().getSessionMap(), ext.getSessionMap());
    

и т. Д.

1 голос
/ 30 января 2014

Работа с рамками, как у 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 показывает способ автоматического обнаружения, который, кажется, требует некоторой настройки: источник

0 голосов
/ 22 октября 2012

Если вы действительно хотите взаимодействовать с имитациями в своих интеграционных тестах (например, одна из причин может заключаться в том, что у вас еще нет полноценной реализации или у вас есть фасад для внешних систем, которые вы не можете контролировать)Есть довольно простой способ интегрировать Mockito с вашими тестами Arquillian, посмотрите на этот пример из демонстрации .Это собственно расширение, но не выпущенное как единое целое.

...