java 如何使用 Arquillian 模拟服务?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5147344/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 09:42:14  来源:igfitidea点击:

How to mock services with Arquillian?

javajakarta-eemockingejbjboss-arquillian

提问by Teliatko

Is it possible to use some kind of mocking framework with Arquillian, or precisely how to mock injected EJBs? I know that, with using the CDI (Contexts and Dependency Injection), it is possible to inject alternatives in test. But without CDI as injection mechanism, when I'm only using EJB injection, how this is possible?

是否可以在 Arquillian 中使用某种模拟框架,或者准确地说如何模拟注入的 EJB?我知道,通过使用 CDI(上下文和依赖注入),可以在测试中注入替代方案。但是没有CDI作为注入机制,当我只使用EJB注入时,这怎么可能?

Recently I have tested my EJBs with service interface mock implementation as following:

最近我用服务接口模拟实现测试了我的 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"));

This approach is possible but requires a lot of custom mock implementations. What is worse, injected instances of mocks are proxies and uses service interface. These can not be cast to mock implementation class to compare results. Only static members and methods of mock implementation can be used.

这种方法是可行的,但需要大量自定义模拟实现。更糟糕的是,模拟的注入实例是代理并使用服务接口。这些不能转换为模拟实现类来比较结果。只能使用模拟实现的静态成员和方法。

I have tested also another possibilities to set related EJBs manually. This approach has several draw-backs. It requires that target EJB of test has non-private members or setters for them. When target EJB relies on @PostConstruct lifecycle annotation, you have to call it after your manual "injection" setting. Advantage of this solution is the ability to use mock frameworks, like mockito or jMock.

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

Have someone an experience to share, how to test and set-up such integration test, or even use mocking frameworks in it ?

有没有人分享一下,如何测试和设置这样的集成测试,甚至在其中使用mocking框架?

回答by Cloves Almeida

IMO, EJBs where not designed with testing in mind. Your alternative sounds like a good enough compromise and I'd go for it. Using mockito is a major plus and I use it even when working with CDI.

IMO,EJB 在设计时没有考虑到测试。你的选择听起来是一个足够好的妥协,我会去的。使用 mockito 是一大优势,即使在使用 CDI 时我也会使用它。

I'd use the "default" member scope and javadoc to other developers access them for testing purposes only.

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

回答by peater

This article from Oracle shows an approach to "injecting" an EJB for testing using JUnit and Mockito: http://www.oracle.com/technetwork/articles/java/unittesting-455385.html

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

Edit: Basically the inclusion of Mockito allows for mocking objects like EntityManager etc.:

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

import static org.mockito.Mockito.*;

...

...

em = mock(EntityManager.class);

They show the approach for EJB as well using mockito. Given an EJB:

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

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

 @Inject
 Event<Result> eventListener;

The test can "inject" those objects:

测试可以“注入”这些对象:

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);
 }

Note that MyResource and MyResource are in the same class path but different source folders so your tests have access to the protected fields, companyand eventListener.

请注意, MyResource 和 MyResource 位于相同的类路径中,但位于不同的源文件夹中,因此您的测试可以访问受保护的字段,company并且eventListener.



Edit:

编辑:

Note: you can use FacesMockitoRunnerfrom JBoss (https://community.jboss.org/thread/170800) to get this done for the common JSF components and use annotations for the others (Java EE 6 with CDI enabled as a pre-requisite for this, but does not require JBoss server):

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

  1. Include jsf, mockito, and jsf-mockito dependencies in 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. Add the @RunWithannotation to your test:

    @RunWith(FacesMockitoRunner.class)
    public class MyTest {
    
  3. Inject common Faces objects using annotations:

    @Inject
    FacesContext facesContext;
    @Inject
    ExternalContext ext;
    @Inject
    HttpServletRequest request;
    
  4. Mock any other objects using the annotations @org.mockito.Mock(it appears FacesMockitoRunnercalls this behind the scenes so it may not be necessary here):

    @Mock MyUserService userService;
    @Mock MyFacesBroker broker;
    @Mock MyUser user;
    
  5. Init the Injected Mocks using the

    @Before public void initMocks() {
        // Init the mocks from above
        MockitoAnnotations.initMocks(this);
    }
    
  6. Setup your test as usual:

    assertSame(FacesContext.getCurrentInstance(), facesContext);
    when(ext.getSessionMap()).thenReturn(session);
    assertSame(FacesContext.getCurrentInstance().getExternalContext(), ext);
    assertSame(FacesContext.getCurrentInstance().getExternalContext().getSessionMap(), ext.getSessionMap());
    
  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. 使用注解注入常见的 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());
    

etc.

等等。

回答by Michael Yakobi

You may want to take a look at testfun-JEEwhich allows you to unit-test (not integration-test) your EJBs outside of a container. testfun-JEE takes care for injecting EJBs as well as EntityManager and some standard resource directly into your test class - references within these EJBs to other EJBs are resolved automatically.

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

And the coolest thing is that you can mock any dependency by simple adding a member variable to your test annotated with @Mock- testfun-JEE will inject this mock wherever needed.

最酷的事情是你可以通过简单地向你的测试添加一个成员变量来模拟任何依赖项@Mock- testfun-JEE 将在需要的地方注入这个模拟。

See examples in https://github.com/michaelyaakoby/testfun.

请参阅https://github.com/michaelyaakoby/testfun 中的示例。

BTW, while this framework was published very recently (like today...) it is being widely used for over a year in my company.

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

回答by Steven

Work with a framework, like Mockito.

使用框架,如 Mockito。

Unfortunately, Arquillian does not automatically include the necessary dependencies. You can add them in your @Deploymentfunction:

不幸的是,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))  
        );  
}  

source

来源

Then in your @Testmethod you could use:

然后在你的@Test方法中你可以使用:

mock(MockedService.class).methodName()

This github showcase shows a way to allow auto discovery, which seems to require some setup: source

这个 github 展示展示了一种允许自动发现的方法,这似乎需要一些设置:

回答by bartosz.majsak

If you really want to interact with mocks in your integration tests (for instance one reason might be that you don't have a full blown implementation yet or you have an facade to external systems which you don't have control over), there is quite an easy way to integrate Mockito with your Arquillian tests, have a look at this example from the showcase. It's actually extension on its own, but not released as one.

如果你真的想在你的集成测试中与模拟交互(例如,一个原因可能是你还没有一个完整的实现,或者你有一个你无法控制的外部系统的外观),有将 Mockito 与您的 Arquillian 测试集成的一种非常简单的方法,请查看展示中的这个示例。它实际上是它自己的扩展,但没有作为一个扩展。