如何使用 Arquillian 模拟服务?
是否可以在 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。
有人可以分享经验,如何测试和设置此类集成测试,甚至在其中使用模拟框架?
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?
Recently I have tested my EJBs with service interface mock implementation as following:
// 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.
Have someone an experience to share, how to test and set-up such integration test, or even use mocking frameworks in it ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
IMO,EJB 的设计并没有考虑到测试。你的替代方案听起来是一个足够好的妥协方案,我会选择它。使用mockito 是一个主要优点,即使在使用CDI 时我也会使用它。
我将使用“默认”成员范围和 javadoc 来让其他开发人员仅出于测试目的访问它们。
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.
I'd use the "default" member scope and javadoc to other developers access them for testing purposes only.
Oracle 的这篇文章展示了一种使用 JUnit 和 Mockito“注入”EJB 进行测试的方法:
http://www.oracle.com/technetwork/articles/java/unittesting -455385.html
编辑:
基本上,Mockito 的包含允许模拟 EntityManager 等对象:
...
它们展示了 EJB 的方法以及使用mockito。给定一个 EJB:
测试可以“注入”这些对象:
请注意,MyResource 和 MyResource 位于同一类路径中,但位于不同的源文件夹中,因此您的测试可以访问受保护的字段
company
和事件监听器
。编辑:
注意:您可以使用 JBoss 的
FacesMockitoRunner
(https://community.jboss .org/thread/170800)为常见的 JSF 组件完成此操作,并为其他组件使用注释(启用 CDI 的 Java EE 6 作为此操作的先决条件,但不需要 JBoss 服务器):将
@RunWith
注释添加到您的测试中:使用注释注入常见的 Faces 对象:
<前><代码>@Inject
FacesContext facesContext;
@注入
外部上下文扩展;
@注入
HttpServletRequest请求;
使用注释模拟任何其他对象
@org.mockito.Mock
(看起来FacesMockitoRunner
调用这是在幕后进行的,因此这里可能没有必要):使用
初始化注入的模拟
照常设置测试来初始化 :
等等。
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
Edit:
Basically the inclusion of Mockito allows for mocking objects like EntityManager etc.:
...
They show the approach for EJB as well using mockito. Given an EJB:
The test can "inject" those objects:
Note that MyResource and MyResource are in the same class path but different source folders so your tests have access to the protected fields,
company
andeventListener
.Edit:
Note: you can use
FacesMockitoRunner
from 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):Include jsf, mockito, and jsf-mockito dependencies in maven:
Add the
@RunWith
annotation to your test:Inject common Faces objects using annotations:
Mock any other objects using the annotations
@org.mockito.Mock
(it appearsFacesMockitoRunner
calls this behind the scenes so it may not be necessary here):Init the Injected Mocks using the
Setup your test as usual:
etc.
您可能想看看 testfun-JEE 它允许您进行单元测试(而不是集成测试) )容器外部的 EJB。
testfun-JEE 负责将 EJB 以及 EntityManager 和一些标准资源直接注入到您的测试类中 - 这些 EJB 中对其他 EJB 的引用会自动解析。
最酷的是,您可以通过简单地将成员变量添加到用
@Mock
注释的测试中来模拟任何依赖项 - testfun-JEE 将在需要的地方注入此模拟。请参阅 https://github.com/michaelyaakoby/testfun 中的示例。
顺便说一句,虽然这个框架是最近发布的(就像今天......),但它在我的公司广泛使用了一年多。
You may want to take a look at testfun-JEE which 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.
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.See examples in 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.
使用框架,例如 Mockito。
不幸的是,Arquillian 不会自动包含必要的依赖项。
您可以将它们添加到您的
@Deployment
函数中:source
然后在您的您可以使用的
@Test
方法:这个 github 展示展示了一种允许自动发现的方法,这似乎需要一些设置:
来源
Work with a framework, like Mockito.
Unfortunately, Arquillian does not automatically include the necessary dependencies.
You can add them in your
@Deployment
function:source
Then in your
@Test
method you could use:This github showcase shows a way to allow auto discovery, which seems to require some setup:
source
如果您确实想在集成测试中与模拟进行交互(例如,一个原因可能是您还没有完整的实现,或者您有一个无法控制的外部系统的外观),那么有将 Mockito 与 Arquillian 测试集成的一种非常简单的方法,请查看 这个展示中的示例。它实际上是一个独立的扩展,但没有作为一个版本发布。
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.