Spring Boot JPA集成测试:TestEntityManager创建失败及构造器异常
我帮你梳理下问题根源和解决办法,你遇到的异常本质是自动配置与自定义配置的冲突导致的,下面一步步来解决:
核心原因分析
@DataJpaTest是Spring Boot提供的切片测试注解,它会自动帮你配置嵌入式数据库、JPA组件(包括TestEntityManager)。但当你通过@ContextConfiguration手动指定自定义的TestPersistenceConfig时,自动配置的TestDatabaseAutoConfiguration会和你的自定义数据源配置冲突——这个自动配置类里的EmbeddedDataSourceFactoryBean是私有内部类,冲突场景下Spring尝试实例化它时就会抛出"无可见构造器"的异常。
解决方案步骤
1. 调整测试类注解,消除配置冲突
既然你已经自定义了完整的JPA持久化配置,就不需要依赖@DataJpaTest的自动配置了。修改测试类如下:
@RunWith(SpringRunner.class) @ActiveProfiles("test") @ContextConfiguration(classes = {TestPersistenceConfig.class}) @Transactional // 保持测试事务性,测试结束自动回滚数据 public class ConfigRepositoryTest { @Autowired private EntityManager entityManager; // 用标准EntityManager代替TestEntityManager @Autowired private ConfigRepository configRepository; @Test public void test1() { // 如果需要TestEntityManager的封装功能,可以手动实例化: // TestEntityManager testEntityManager = new TestEntityManager(entityManager); Config config = configRepository.findByKey(ConfigKey.PURGE_DATE_RETENTION_CALENDAR_TYPE); assertNotNull(config); } }
如果一定要用TestEntityManager,直接通过注入的标准EntityManager手动实例化即可,它本质是对标准EntityManager的封装。
2. 修正JPA配置的属性前缀错误
你的TestPersistenceConfig里的Hibernate属性多了无效的em.前缀,这会导致Hibernate无法识别这些配置,同时测试用H2数据库却配置了Oracle方言,容易引发SQL兼容问题,修正如下:
private Properties additionalProperties() { Properties hibernateProperties = new Properties(); // 去掉无效的em.前缀 hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "none"); hibernateProperties.setProperty("hibernate.show_sql", "true"); hibernateProperties.setProperty("hibernate.format_sql", "true"); hibernateProperties.setProperty("hibernate.naming.physical-strategy", "org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl"); // 测试用H2数据库,改用H2方言 hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); return hibernateProperties; }
3. 简化Maven依赖,避免版本冲突
spring-boot-starter-test已经包含了JUnit 5、Mockito等核心测试依赖,不需要重复引入;同时建议用spring-boot-starter-data-jpa代替单独的Hibernate依赖,Spring Boot会帮你管理版本兼容性:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <scope>test</scope> </dependency> <!-- 补充PowerMock的JUnit4模块依赖 --> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <scope>test</scope> </dependency> </dependencies>
备选方案:保留@DataJpaTest的同时使用自定义配置
如果你想保留@DataJpaTest的切片测试特性,可以通过注解禁用自动配置的嵌入式数据库,这样就能兼容你的自定义数据源:
@RunWith(SpringRunner.class) @DataJpaTest @ActiveProfiles("test") @ContextConfiguration(classes = {TestPersistenceConfig.class}) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) public class ConfigRepositoryTest { // 你的测试代码 }
内容的提问来源于stack exchange,提问作者horizon7

