如何在 SE 环境中同时使用 Weld 和 EclipseLink?

How do I use Weld and EclipseLink together in an SE environment?

我正在尝试创建一个通过 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

之间没有关系

我需要将 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 class。在测试期间,它将从容器实例设置实体管理器。

@ApplicationScoped
public class JpaProvider {

    private EntityManager em;

    @Produces
    public EntityManager getEntityManager() {

        return em;
    }

    @PersistenceContext
    public void setEntityManager(final EntityManager em) {

        this.em = em;
    }
}

您的解决方案听起来很笨拙,据我了解您需要更改被测代码(这不是一件好事 (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
    }
}