Mat*_*ell 14 unit-testing ejb jax-rs jersey
我很高兴学习JAX-RS和Jersey,但我遇到了试图测试需要注入DAO的简单资源的障碍,如下所示:
@Stateless
@Path("simple")
public class SimpleResource {
@PersistenceContext
private EntityManager em;
// @GET, etc...
}
Run Code Online (Sandbox Code Playgroud)
(我将转向更抽象的DAO模式,但问题是一样的,即如何注入@EJB DAO?)
在我的单元测试中,我使用嵌入式Jetty服务器在其web.xml中配置Jersey,我想挂钩资源的生命周期,以便我可以注入一个模拟EntityManager,但我没有找到一个干净的答案经过大量的搜索.你能帮我吗?我遇到的一些可能的方向:
1)在我的代码中使用JNDI上下文查找来获取DAO bean,并在测试中注册模拟对象.
而不是@EJB或@PersistenceContext,在资源的构造函数中使用这样的东西:
theDAO = (DAOImpl) new InitialContext().lookup("java:global/EJB/DAOImpl");
Run Code Online (Sandbox Code Playgroud)
但是,这意味着我的测试环境需要支持JNDI,而在Jetty中这样做可能会带来一些痛苦.另外,它不使用干净的注释方法.
2)使用方法注射.
注入方法,以便我可以设置DAO后实例化,例如,
@PersistenceContext(name = "persistence/pu00")
public void setPersistenceUnit00(final EntityManager em) {
em00 = em;
}
Run Code Online (Sandbox Code Playgroud)
要么
private MyEjbInterface myEjb;
@EJB(mappedName="ejb/MyEjb")
public void setMyEjb(MyEjb myEjb) {
this.myEjb = myEjb;
}
Run Code Online (Sandbox Code Playgroud)
但是,要做到这一点,我需要Jersey实例化的实例,例如,SimpleResource.我怎么做到的?
3)使用反射.
一种DIY注射,如:
public static void setPrivateField(Class<? extends Object> instanceFieldClass, Object instance, String fieldName, Object fieldValue) {
Field setId = instanceFieldClass.getDeclaredField(fieldName);
setId.setAccessible(true);
setId.set(instance, fieldValue);
}
Run Code Online (Sandbox Code Playgroud)
同样,我需要Jersey实例化的实例.
4)使用注射提供者.
我仍然粗略地说明它是如何工作的,但看起来Jersey提供了一种定义可定制注射注释的方法,例如,
@Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
if (!(t instanceof Class)) {
return null;
}
try {
Class c = (Class) t;
Context ic = new InitialContext();
final Object o = ic.lookup(c.getName());
return new Injectable<Object>() {
public Object getValue() {
return o;
}
};
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用辅助类的变体:
Server server = new Server(8080);
Context root = new Context(server,"/",Context.SESSIONS);
ResourceConfig rc = new PackagesResourceConfig("edu.mit.senseable.livesingapore.platform.restws.representations");
rc.getSingletons().add(new SingletonTypeInjectableProvider<javax.ws.rs.core.Context, Myobj>(Myobj.class, new Myobj(12,13)){});
root.addServlet(new ServletHolder(new ServletContainer(rc)), "/");
server.start();
Run Code Online (Sandbox Code Playgroud)
有了这个用途:
@Path("/helloworld")
public class HelloWorldResource {
@Context Myobj myClass;
....
}
Run Code Online (Sandbox Code Playgroud)
这对@EJB或@PersistenceContext是否可行?
5)扩展javax.ws.rs.core.Application.
粗略对此,但是:
@javax.ws.rs.ApplicationPath("application")
public class InjectionApplication extends javax.ws.rs.core.Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public InjectionApplication() {
// no instance is created, just class is listed
classes.add(BookResource.class);
}
@Override
public Set<Class<?>> getClasses() {
return classes;
}
@Override
public Set<Object> getSingletons() {
return singletons;
}
}
Run Code Online (Sandbox Code Playgroud)
6)扩展ServletContainer.
使用InjectableProvider的旧式?看起来更复杂:
public class ServletAdapter extends ServletContainer {
@Override
protected void configure(ServletConfig servletConfig, ResourceConfig rc, WebApplication wa) {
super.configure(servletConfig, rc, wa);
rc.getSingletons().add(new InjectableProvider<Resource, Type>() {
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
public Injectable<Object> getInjectable(ComponentContext ic, Resource r, Type c) {
final Holder value = new Holder();
Context ctx = new InitialContext();
try {
value.value = ctx.lookup(r.name());
} catch (NamingException ex) {
value.value = ctx.lookup("java:comp/env/" + r.name());
}
return new Injectable<Object>() {
public Object getValue() {
return value.value;
}
};
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
7)使用嵌入式EJB容器.
例如,http://openejb.apache.org.这非常沉重,我预计工作会变得很混乱.(事实上,让我沿着"Jetty + Jersey"路线开始的是GlassFish Embedded中围绕安全登录的一个错误.我还查看了其他Java EE 6应用程序容器,如JBoss AS,但每个都有嵌入式模式的问题,用户有限社区支持.)
8)使用Spring或Guice等第三方IoC库.
Spring显然常用于解决这些问题(在单元测试时注入模拟),但我想避免学习另一大套API - 纯Java EE已经足够挑战了!但如果这是最好的解决方案我就是游戏.我还没有仔细看过Spring或Guice.
你成功使用过这些吗?您喜欢的其他任何解决方案 我真的很期待你的建议.提前谢谢 - 亚光
如果您只需要一个EntityManager
内置的 Jetty 容器,为什么首先要使用注入呢?您可以将 JPA 实现之一(例如 eclipselink 或 hibernate)放在类路径上,配置资源本地持久性单元,然后按如下方式获取它:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("your unit name");
EntityManager em = emf.createEntityManager();
Run Code Online (Sandbox Code Playgroud)
@EJB
为了测试 JAX-RS 类,拥有一些行为类似于您的东西(也许是静态 DAO 工厂?)就足够了。
如果您确实希望单元测试尽可能接近 Java EE 环境,请考虑使用 Arquillian (http://www.jboss.org/arquillian.html) 运行它们。它直接在 Java EE 容器上运行测试 - 这很简单,并且有很棒的文档。
归档时间: |
|
查看次数: |
3085 次 |
最近记录: |