JUnit 5+EE8环境下SE测试通过CDI获取替代EntityManager咨询
解决方案:激活CDI替代并在JUnit 5 SE测试中获取Mock EntityManager
你的核心问题是没有正确激活自定义的MockResources替代类,反而错误地在beans.xml中指定了Hibernate的SessionImpl,这完全不符合CDI替代的规则。下面是一步步的修正方案:
1. 修正MockResources的注解配置
首先调整你的MockResources,确保它的作用域和替代标识匹配原生产者的配置,避免CDI容器出现歧义:
import javax.enterprise.inject.Alternative; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; import javax.persistence.EntityManager; import javax.persistence.Persistence; @Alternative // 标记为CDI替代类 @ApplicationScoped // 和原Resources的作用域保持一致 public class MockResources { @Produces public EntityManager getEntityManager() { // 建议使用测试专用的PU(比如内存H2数据库),避免污染生产数据 return Persistence.createEntityManagerFactory("primary-test") .createEntityManager(); } }
提示:如果坚持用
primaryPU,请确保测试时连接的是测试数据库,而非生产库。
2. 配置测试专用的beans.xml
在测试资源目录下创建src/test/resources/META-INF/beans.xml,专门用于激活你的替代类,不要修改主程序的beans.xml:
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-discovery-mode="all"> <!-- 激活自定义的MockResources替代类 --> <alternatives> <class>你的实际包路径.MockResources</class> <!-- 替换成真实的全类名 --> </alternatives> </beans>
这里的关键是:CDI的@Alternative是用来替换整个bean/生产者类,而非底层实现类,所以你要激活的是自己写的MockResources,不是Hibernate的SessionImpl。
3. 在JUnit 5测试中获取CDI管理的EntityManager
要在SE环境的JUnit测试中使用CDI,需要引入Weld SE容器和JUnit 5扩展,实现依赖注入:
3.1 添加测试依赖(Maven示例)
在pom.xml中加入以下依赖:
<dependencies> <!-- JUnit 5核心依赖 --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.9.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.9.2</version> <scope>test</scope> </dependency> <!-- Weld SE:SE环境下的CDI容器 --> <dependency> <groupId>org.jboss.weld.se</groupId> <artifactId>weld-se-core</artifactId> <version>4.0.3.Final</version> <scope>test</scope> </dependency> <!-- Weld JUnit 5扩展:让JUnit测试支持CDI注入 --> <dependency> <groupId>org.jboss.weld.junit5</groupId> <artifactId>weld-junit5</artifactId> <version>4.0.3.Final</version> <scope>test</scope> </dependency> </dependencies>
3.2 编写JUnit 5测试类
使用@EnableWeld启动CDI容器,直接注入EntityManager即可:
import org.junit.jupiter.api.Test; import org.jboss.weld.junit5.EnableWeld; import javax.inject.Inject; import javax.persistence.EntityManager; import static org.junit.jupiter.api.Assertions.assertNotNull; @EnableWeld // 启动Weld CDI容器 public class EntityManagerMockTest { @Inject private EntityManager entityManager; // 这里会自动注入MockResources生产的实例 @Test void testEntityManagerInjection() { assertNotNull(entityManager); // 在这里编写你的业务测试逻辑,比如持久化测试实体、查询验证等 } }
关键原理说明
- CDI的
@Alternative是候选替代类,必须在beans.xml中显式激活才会覆盖原bean。 - 测试环境使用独立的
beans.xml,可以避免测试配置影响生产代码。 - Weld SE和JUnit 5扩展让SE环境也能完整使用CDI的依赖注入能力,完美适配你的测试场景。
内容的提问来源于stack exchange,提问作者Fabrizio Stellato
相关产品推荐
相关产品推荐

