如何在SE环境中一起使用Weld和EclipseLink?

时间:2017-05-11 21:14:17

标签: unit-testing jpa weld

我正在尝试创建一个通过JPA使用EclipseLink的单元测试,我注意到我需要将一个DAO注入一个监听器。代码本身在容器内按预期工作,但我无法对其进行单元测试。

听众看起来像这样。

@ApplicationScoped
public class ParticipantListener {

    @Inject
    private ParticipantDAO dao;

    @PrePersist
    @PreUpdate
    void ensureNoDuplicateSin(final Participant e) throws DuplicateSinException {

        final Participant bySin = dao.getBySinAndNotSelf(e.getSin(), e);
        if (bySin != null && bySin.getId() != e.getId()) {
            throw new DuplicateSinException();
        }
    }
}

当我在单元测试中运行dao时没有注入。

我的测试初始化​​如下:

    weld = new Weld();
    final WeldContainer container = weld.initialize();
    vf = Validation.buildDefaultValidatorFactory();
    final Map<String, String> props = new HashMap<>();
    props.put("javax.persistence.provider", "org.eclipse.persistence.jpa.PersistenceProvider");
    emf = Persistence.createEntityManagerFactory("test-pu", props);
    em = emf.createEntityManager();

显然不应该有效,因为em/emfcontainer

之间没有任何关系

2 个答案:

答案 0 :(得分:0)

我需要将javax.persistence.bean.manager设置为指向Weld的bean管理器。另外我发现我也是

    weld = new Weld();
    final WeldContainer container = weld.initialize();
    final JpaProvider jpaProvider = container.select(JpaProvider.class).get();

    final Map<String, Object> props = new HashMap<>();
    props.put("javax.persistence.provider", "org.eclipse.persistence.jpa.PersistenceProvider");
    props.put("javax.persistence.bean.manager", container.getBeanManager());
    emf = Persistence.createEntityManagerFactory("test-pu", props);
    em = emf.createEntityManager();
    jpaProvider.setEntityManager(em);

此外,我必须将DAO更改为不使用@PersistenceContext并使用@Inject作为实体管理器并创建JpaProvider类。在测试期间,它将从容器实例中设置实体管理器。

@ApplicationScoped
public class JpaProvider {

    private EntityManager em;

    @Produces
    public EntityManager getEntityManager() {

        return em;
    }

    @PersistenceContext
    public void setEntityManager(final EntityManager em) {

        this.em = em;
    }
}

答案 1 :(得分:0)

您的解决方案听起来很笨拙,据我所知,您需要更改测试中的代码(这不是一件好事(TM))。

而是查看arquillian(http://arquillian.org/)以及与mockito一起使用。

这里有一些样板代码,显示了我通常如何做到这一点:

@RunWith(Arquillian.class)
public class TestParticipantListener {
    // Collection of producer methods and/or static producer fields
    // that mock the injected dependencies for the class under test
    public static class LocalMocks {
        @Produces ParticipantDAO getParticipantDAO() {
            ParticipantDAO participantDAO = Mockito.mock(...);
            return participantDAO
        }
    }

    @Deployment
    public static WebArchive createDeployment() {
        PomEquippedResolveStage pom = Maven.resolver().loadPomFromFile("pom.xml");
        BeansDescriptor beansXml = Descriptors.create(BeansDescriptor.class)
            .addDefaultNamespaces().getOrCreateAlternatives()
            .up();

        WebArchive jar = ShrinkWrap.create(WebArchive.class)
            .addAsLibraries(pom.resolve("org.mockito:mockito-core").withTransitivity().asFile())
            .addClass(ParticipantListener.class)
            .addClass(ParticipantDAO.class)
            .addClass(TestParticipantListener.LocalMocks.class)
            // ... other dependencies
            .addAsWebInfResource(new StringAsset(beansXml.exportAsString()), "beans.xml");

        return jar;
    }

    @Inject ParticipantListener participantListenerUnderTest;

    @Test
    public void test() {
        ... whatever your test is, using the injected instance
    }
}