You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 02:38:19