已添加注解但@Autowired注入的movieRepository仍为空问题排查
问题描述
编写MongoDB集成测试时,@Autowired注入的MovieRepository字段抛出NullPointerException。已知MongoRepository无需添加@Repository注解(添加后问题未解决),测试类继承的抽象类已标注@DataMongoTest,但问题依然存在。
代码与环境信息
环境
- Java 17
- Spring Boot 3.0 RC1
- JUnit 5
- Maven
- 依赖:Spring Web、Spring Data MongoDB、Lombok、Testcontainers
相关代码
MovieRepository.java(/main/目录)
package com.example.testingtwo.repository; public interface MovieRepository extends MongoRepository<Movie, String> { }
AbstractContainerBaseTest.java(/test/目录)
package com.example.testingtwo; @DataMongoTest public abstract class AbstractContainerBaseTest { static final MongoDBContainer mongoDBContainer; static { mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6.0.2")); mongoDBContainer.start(); } @DynamicPropertySource static void setProperties(DynamicPropertyRegistry registry) { registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); } }
MovieRepositoryIntegrationTest.java(/test/目录)
package com.example.testingtwo.repository; public class MovieRepositoryIntegrationTest extends AbstractContainerBaseTest { @Autowired private MovieRepository movieRepository; @AfterEach void cleanUp() { movieRepository.deleteAll(); } @Test public void testFindById() { Movie movie = new Movie(null, "Test Name", "Test Description"); String movieId = movieRepository.save(movie).getId(); // 抛出NullPointerException: this.movieRepository is null Movie movieFound = movieRepository.findById(movieId).orElse(null); assertNotNull(movieFound); assertEquals(movieFound.getName(), movie.getName()); assertEquals(movieFound.getDescription(), movie.getDescription()); } }
解决方案
问题出在测试子类MovieRepositoryIntegrationTest未被Spring Boot测试上下文正确加载。虽然抽象类标注了@DataMongoTest,但该注解不会自动让子类被Spring测试框架识别并初始化上下文。
修复步骤
在MovieRepositoryIntegrationTest类上添加@DataMongoTest注解,确保Spring Boot测试框架启动MongoDB切片测试上下文,完成依赖注入:
package com.example.testingtwo.repository; @DataMongoTest // 添加该注解 public class MovieRepositoryIntegrationTest extends AbstractContainerBaseTest { @Autowired private MovieRepository movieRepository; // 其余代码不变 }
可选优化
如果希望抽象类仅负责Testcontainers配置,可将@DataMongoTest移到子类,移除抽象类上的该注解,结构更清晰:
修改后的AbstractContainerBaseTest.java
package com.example.testingtwo; // 移除@DataMongoTest public abstract class AbstractContainerBaseTest { static final MongoDBContainer mongoDBContainer; static { mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6.0.2")); mongoDBContainer.start(); } @DynamicPropertySource static void setProperties(DynamicPropertyRegistry registry) { registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); } }
修改后的MovieRepositoryIntegrationTest.java
package com.example.testingtwo.repository; @DataMongoTest public class MovieRepositoryIntegrationTest extends AbstractContainerBaseTest { // 其余代码不变 }
原理说明
@DataMongoTest是Spring Boot提供的切片测试注解,用于启动仅包含MongoDB相关组件的测试上下文。只有当测试类直接标注该注解时,Spring才会初始化上下文并完成依赖注入,抽象类的注解不会自动传递给子类生效。
内容的提问来源于stack exchange,提问作者Luigi Loria

