使用org.jglue.cdi-unit进行单元测试时,EntityManager为null

fat*_*ihn 3 junit jpa java-ee cdi cdi-unit

这是单元测试代码.当我们运行单元测试代码(SampleServiceTest2)时; 在AbstractDao中注入的EntityManager始终为null!我们如何在单元测试期间注入em.

***SampleServiceTest2.java

import javax.inject.Inject;

import org.jglue.cdiunit.CdiRunner;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(CdiRunner.class)
public class SampleServiceTest2 {

    @Inject SampleService greeter; 

    @Test
    public void testGreeter() throws Exception { 
        System.out.println("before2");
        greeter.addSampleData(new SampleDataDto(), new KullaniciDto()); 
        System.out.println("after2");
    } 
}
Run Code Online (Sandbox Code Playgroud)

***SampleService.java

import javax.ejb.Stateless;
import javax.inject.Inject;
....

@Stateless
@SecuredBean
public class SampleService {

    @Inject 
    SampleLogic sampleLogic;

    @Yetki(tag="perm_add_sample_data")
    public void addSampleData(SampleDataDto data, KullaniciDto aktifKullaniciDto){
        SampleDataHelper sampleDataHelper = new SampleDataHelper();

        SampleData sampleData = sampleDataHelper.getEntity(data);
        KullaniciHelper kullaniciHelper = new KullaniciHelper();

        Kullanici kullanici = kullaniciHelper.getEntity(aktifKullaniciDto);
        sampleLogic.addData(sampleData, kullanici);
    }

}
Run Code Online (Sandbox Code Playgroud)

****SampleLogic.java

import javax.inject.Inject;

....

public class SampleLogic {
    @Inject 
    SampleDataDao sampleDataDao;

    public void addData(SampleData data, Kullanici kullanici) {
        addData1(data,kullanici);   
        System.out.println("SampleLogic : addData() called!");
    }

    public void addData1(SampleData data, Kullanici kullanici) {
        sampleDataDao.create(data, kullanici);
    }
}
Run Code Online (Sandbox Code Playgroud)

****SampleDataDao.java

public class SampleDataDao extends AbstractDao<SampleData> {
    private static final long serialVersionUID = 1L;
}
Run Code Online (Sandbox Code Playgroud)

****AbstractDao.java

public abstract class AbstractDao<T extends BaseEntity> implements Serializable {

    private static final long serialVersionUID = 1L;

    @PersistenceContext(unitName="meopdb")
    private EntityManager em;

    protected EntityManager getEm() {
        return em;
    }

    @SuppressWarnings("rawtypes")
    private Class entityClass;


    @SuppressWarnings("rawtypes")
    private Class getEntityClass() {
        if (entityClass == null) {
            entityClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return entityClass;
    }

    public T create(T t, Kullanici kullanici) {
        if (t.getId() != null) {
            throw new IllegalStateException("Create Operation: Oid should be null");
        }
        t.setId(getSeqNextValue(t));
        t.setEklemeZamani(new Timestamp(Calendar.getInstance().getTimeInMillis()));
        t.setEkleyenKullaniciId(kullanici.getId());

        t.setDurumId(EnumDurum.AKTIF.getValue());

        t = em.merge(t);
        em.flush();
        return t;
    }
}
Run Code Online (Sandbox Code Playgroud)

Ond*_*Mih 8

如果您使用CDIUnit进行测试,您唯一得到的就是CDI注入,而不是Java EE的全部功能.使用@PersistenceContextinto 注入entityManager AbstractDAO不是独立CDI的一部分,仅当应用程序在Java EE应用程序服务器中运行时才支持它.

解决方案是使用CDI机制注入EntityManager并创建生成器.然后可以在单元测试中切换生产者以提供测试实体管理器.但是,在独立单元测试中设置JPA并不是那么简单,因为您需要直接在persistence.xml文件中指定连接属性.另外,不要忘记将JPA实现(hibernate,eclipselink)的依赖项添加到测试依赖项中.

但是,如果您不想调整应用程序的代码,或者在测试中需要的不仅仅是CDI,那么您应该查看Arquillian Java EE测试框架.

以下是CDIUnit的示例:

public abstract class AbstractDao<T extends BaseEntity> implements Serializable {
...
    @Inject
    @Named("meopdb")
    private EntityManager em;
...
}

// producer in application - just a wraper over `@PersisteneContext`
public class EntityManagerProducer {
    @Produces
    @PersistenceContext(unitName="meopdb")
    @Named("meopdb")
    private EntityManager em;
}

/* producer in your test sources - it creates entityManager via API calls instead of injecting via `@PersistenceContext`. Also, a different persistence unit is used so that it does not clash with main persistence unit, which requires datasource from app server 
*/
public TestEntityManagerProducer {
    @Produces
    @ProducesAlternative // CDIUnit annotation to turn this on as an alternative automatically
    @Named("meopdb")
    public EntityManager getEm() {
        return Persistence
                .createEntityManagerFactory("meopdb-test")
                .createEntityManager();
    }

}
Run Code Online (Sandbox Code Playgroud)

它还不够.您需要persistence.xml使用名为"meopdb-test"的测试持久性单元在测试资源中创建一个新的.对于此单元,您需要指定RESOURCE_LOCAL transaction-type并指定连接信息.最后一件事不要忘记 - 您需要在persistence.xml或外部orm文件中列出所有实体.这是因为您的测试在应用程序服务器之外运行.在应用内部服务器中,JPA可以自动查找实体.