使用Testcontainers进行Spring Data JPA测试时Repository自动装配失败,抛空指针异常
问题分析与解决方案
你的问题出在两个核心点:JUnit版本混合使用导致Spring测试上下文未初始化,以及**@DynamicPropertySource用法错误**,最终导致UserRepository无法被自动装配,抛出空指针异常。
具体修复步骤
1. 统一使用JUnit 5(Jupiter)API
测试类中混合了JUnit 4的org.junit.Test注解和JUnit 5的org.junit.jupiter.api.Assertions,这会导致测试引擎无法正确触发Spring上下文初始化,@Autowired的Bean自然无法注入。
2. 修正@DynamicPropertySource的用法
原代码中用ConfigurableEnvironment设置系统属性的方式是错误的,Spring Boot与Testcontainers集成时,@DynamicPropertySource需要接收DynamicPropertyRegistry参数来注册数据源属性。
修复后的完整测试代码
package org.mwdziak.vaccinationbackend.repository; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Assertions; import org.mwdziak.vaccinationbackend.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.test.context.DynamicPropertySource; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import java.time.LocalDate; @DataJpaTest @Testcontainers @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) public class UserRepositoryTests { @Autowired private UserRepository userRepository; @Container static MySQLContainer<?> mySQLContainer = new MySQLContainer<>("mysql:8.0.26") .withDatabaseName("vaccination") .withUsername("vaccination") .withPassword("vaccination"); @DynamicPropertySource static void registerMySqlProperties(org.springframework.test.context.DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", mySQLContainer::getJdbcUrl); registry.add("spring.datasource.username", mySQLContainer::getUsername); registry.add("spring.datasource.password", mySQLContainer::getPassword); } @Test public void should_save_user() { //Arrange var user = User.builder() .password("test") .email("test") .firstName("test") .lastName("test") .dateOfBirth(LocalDate.now()) .role(User.Role.USER) .build(); //Act var saved = userRepository.save(user); //Assert Assertions.assertNotNull(saved); Assertions.assertNotNull(saved.getId()); } }
3. 确保依赖配置正确(可选验证)
如果使用Maven,确保pom.xml中排除JUnit 4的老式引擎,并引入Testcontainers的JUnit 5依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>mysql</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency>
如果使用Gradle:
testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.testcontainers:mysql' testImplementation 'org.testcontainers:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' test { useJUnitPlatform() exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' }
修复说明
- 替换
org.junit.Test为org.junit.jupiter.api.Test,确保测试由JUnit 5引擎执行,正确触发Spring上下文初始化 - 用
DynamicPropertyRegistry替代ConfigurableEnvironment,这是Spring Boot 2.2+与Testcontainers集成的标准方式,保证数据源配置正确加载 - 给
MySQLContainer添加泛型<?>消除编译器警告 - 新增对
saved.getId()的断言,更完整验证用户保存操作
内容的提问来源于stack exchange,提问作者mwdziak
相关产品推荐
相关产品推荐

