如何用阿奎利安模拟服务?

是否有可能在 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 具有非私有成员或 setter。当目标 EJB 依赖于@PostConstruct生命周期注释时,您必须在手动“注入”设置之后调用它。该解决方案的优点是能够使用模拟框架,如mockito或jMock。

有人有经验可以分享,如何测试和设置这样的集成测试,甚至在其中使用模拟框架?


答案 1

IMO,EJB,在设计时没有考虑到测试。你的替代方案听起来像是一个足够好的妥协,我会去的。使用mockito是一个主要的优点,即使在使用CDI时,我也使用它。

我会使用“默认”成员范围和javadoc让其他开发人员仅出于测试目的访问它们。


答案 2

Oracle的这篇文章展示了一种使用JUnit和Mockito“注入”EJB进行测试的方法:http://www.oracle.com/technetwork/articles/java/unittesting-455385.html

编辑:基本上,包含Mockito允许模拟对象,如EntityManager等:

import static org.mockito.Mockito.*;

...

em = mock(EntityManager.class);

他们展示了EJB的方法以及使用mojito的方法。给定一个 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 位于同一类路径中,但源文件夹不同,因此您的测试可以访问受保护的字段,以及 。companyeventListener


编辑:

注意:您可以使用来自 JBoss(https://community.jboss.org/thread/170800)为常见的 JSF 组件完成此操作,并对其他组件使用注释(启用了 CDI 的 Java EE 6 作为先决条件,但不需要 JBoss 服务器):FacesMockitoRunner

  1. 在 maven 中包含 jsf、mockito 和 jsf-mockito 依赖项:

        <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. 使用注释注入常见的人脸对象:

    @Inject
    FacesContext facesContext;
    @Inject
    ExternalContext ext;
    @Inject
    HttpServletRequest request;
    
  4. 使用注释模拟任何其他对象(它似乎在幕后调用它,因此此处可能没有必要):@org.mockito.MockFacesMockitoRunner

    @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());
    

等。


推荐