Unit testing 在JAX-RS单元测试中连接到@EJB或@PersistenceContext注入

Unit testing 在JAX-RS单元测试中连接到@EJB或@PersistenceContext注入,unit-testing,ejb,jersey,jax-rs,Unit Testing,Ejb,Jersey,Jax Rs,我很喜欢学习JAX-RS和Jersey,但我在尝试测试需要注入DAO的简单资源时遇到了一个障碍,比如: @Stateless @Path("simple") public class SimpleResource { @PersistenceContext private EntityManager em; // @GET, etc... } EntityManagerFactory emf = Persistence.createEntityManagerFactory

我很喜欢学习JAX-RS和Jersey,但我在尝试测试需要注入DAO的简单资源时遇到了一个障碍,比如:

@Stateless
@Path("simple")
public class SimpleResource {

    @PersistenceContext
    private EntityManager em;

// @GET, etc...

}
EntityManagerFactory emf = Persistence.createEntityManagerFactory("your unit name");
EntityManager em = emf.createEntityManager();
(我将转向更抽象的DAO模式,但问题是相同的,即如何注入@EJBDAO?)

在我的单元测试中,我使用了一个嵌入式Jetty服务器,该服务器在其web.xml中配置Jersey,我想连接到资源的生命周期中,这样我就可以注入一个模拟EntityManager,但经过大量搜索,我还没有找到一个清晰的答案。你能帮忙吗?我遇到了一些可能的方向:

1)在我的代码中使用JNDI上下文查找来获取DAOBean,并在测试中注册模拟对象。

在资源的构造函数中使用类似以下内容,而不是@EJB或@PersistenceContext:

  theDAO = (DAOImpl) new InitialContext().lookup("java:global/EJB/DAOImpl");
然而,这意味着我的测试环境需要支持JNDI,在Jetty中这样做可能会带来一些麻烦。另外,它没有使用干净的注释方法

2)使用方法注射。

注入到方法中,以便我可以设置DAO后实例化,例如

@PersistenceContext(name = "persistence/pu00")
public void setPersistenceUnit00(final EntityManager em) {
    em00 = em;
}

然而,要做到这一点,我需要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);
}
这对@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;
  }
}
@javax.ws.rs.ApplicationPath(“应用程序”)
公共类注入应用程序扩展了javax.ws.rs.core.Application{
private Set singleton=new HashSet();
私有集>();
公共注入应用程序(){
//没有创建实例,只列出了类
添加(booksource.class);
}
@凌驾

public Set如果在嵌入式Jetty容器中只需要一个
EntityManager
,为什么要首先使用注入?您只需将一个JPA实现(如eclipselink或hibernate)放在类路径上,配置一个资源本地持久化单元,然后按如下方式获得它:

@Stateless
@Path("simple")
public class SimpleResource {

    @PersistenceContext
    private EntityManager em;

// @GET, etc...

}
EntityManagerFactory emf = Persistence.createEntityManagerFactory("your unit name");
EntityManager em = emf.createEntityManager();
为了测试JAX-RS类,有一些行为类似于
@EJB
的东西(可能是静态DAO工厂?)就足够了


如果您确实希望单元测试尽可能接近JavaEE环境,请考虑使用Arquillian运行它们(http://www.jboss.org/arquillian.html)。它直接在Java EE容器上运行测试-很简单,它有很好的文档。

既然您使用的是Netbeans,请尝试一下:


本教程使用嵌入式Glassfish容器并注入一个封装EntityManager的EJB(类似于您在第一个选项中描述的内容).

我建议您看看NetBeans向导从数据库生成RESTFul web服务的方式。您可以查看以下链接:谢谢,perissf。实际上,我的项目是从NetBeans生成的向导开始的。我重新阅读了您链接的文章,但我看不出它们是如何解决我的问题的——它们最终拥有了一个JAX-RS资源eds是容器注入的EntityManager,对吗?这里可能缺少一些新的东西。。。
@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;
  }
}
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;
                }
            };
        }
    });
}
}  
EntityManagerFactory emf = Persistence.createEntityManagerFactory("your unit name");
EntityManager em = emf.createEntityManager();