Java 如何使用Arquillian模拟服务?

Java 如何使用Arquillian模拟服务?,java,jakarta-ee,mocking,ejb,jboss-arquillian,Java,Jakarta Ee,Mocking,Ejb,Jboss Arquillian,有没有可能在Arquillian中使用某种模拟框架,或者确切地说,如何模拟注入的EJB?我知道,通过使用CDI(上下文和依赖注入),可以在测试中注入替代方案。但是如果没有CDI作为注入机制,当我只使用EJB注入时,这怎么可能呢 最近,我使用服务接口模拟实现测试了我的EJB,如下所示: // Service inteface public interface Audit { void audit(String info); } // Mock implementation @Statel

有没有可能在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"));
这种方法是可能的,但需要大量自定义模拟实现。更糟糕的是,注入的mock实例是代理并使用服务接口。这些不能转换为模拟实现类来比较结果。只能使用模拟实现的静态成员和方法

我还测试了手动设置相关EJB的另一种可能性。这种方法有几个缺点。它要求测试的目标EJB具有非私有成员或setter。当目标EJB依赖于@PostConstruct生命周期注释时,您必须在手动“注入”设置之后调用它。 此解决方案的优点是能够使用模拟框架,如mockito或jMock


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

IMO,ejb在设计时没有考虑到测试。你的选择听起来是一个很好的折衷方案,我同意。使用mockito是一个主要的优点,我甚至在使用CDI时也使用它


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

如果您真的想在集成测试中与mock交互(例如,一个原因可能是您还没有一个完整的实现,或者您没有控制的外部系统的外观),有一种非常简单的方法可以将Mockito与Arquillian测试集成在一起,看看。它实际上是一个独立的扩展,但不是作为一个扩展发布的。

这篇来自Oracle的文章展示了一种使用JUnit和Mockito“注入”EJB进行测试的方法:

编辑: 基本上,Mockito的加入允许模拟EntityManager等对象:

import static org.mockito.Mockito.*;

它们还展示了使用mockito实现EJB的方法。给定一个EJB:

@Stateless
public class MyResource {
 @Inject
 Instance<Consultant> company;

 @Inject
 Event<Result> eventListener;
请注意,MyResource和MyResource位于相同的类路径中,但源文件夹不同,因此您的测试可以访问受保护的字段,
company
eventListener


编辑:

注意:您可以使用JBoss()中的
FacesMockitoRunner
来为常见的JSF组件完成此操作,并为其他组件使用注释(Java EE 6启用CDI作为此操作的先决条件,但不需要JBoss服务器):

  • 在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>
    
  • 使用注释插入公共面对象:

    @Inject
    FacesContext facesContext;
    @Inject
    ExternalContext ext;
    @Inject
    HttpServletRequest request;
    
  • 使用注释模拟任何其他对象
    @org.mockito.Mock
    (似乎
    FacesMockitoRunner
    在后台调用此函数,因此此处可能不需要此函数):

  • 使用

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

  • 诸如此类。

    您可能想看看,哪种方法允许您在容器外部对EJB进行单元测试(而不是集成测试)。 testfun JEE负责将EJB、EntityManager和一些标准资源直接注入到测试类中——这些EJB中对其他EJB的引用会自动解析

    最酷的是,你可以通过简单地向你的测试中添加一个成员变量来模拟任何依赖关系,这个变量用
    @mock
    -testfun JEE会在需要的地方注入这个模拟

    请参见中的示例


    顺便说一句,虽然这个框架是最近发布的(比如今天…),但它在我的公司被广泛使用了一年多。

    使用一个框架,比如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 showcase显示了一种允许自动发现的方法,这似乎需要一些设置:

    你能至少解释一下链接的一些内容吗?链接本身会受到“链接腐烂”的影响,这样的努力是值得赞赏的。@EJB类可以与模拟框架(如mockito IMO)的使用一起测试。谁为测试付费,谁负责@EJB类未测试的案例?
    @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());
    
    @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))  
            );  
    }  
    
    mock(MockedService.class).methodName()