
在开发spring boot应用时,编写集成测试是确保代码质量的关键环节。我们常常使用@springboottest结合@autowired来注入服务或数据访问层(repository)进行测试。然而,有时即使配置了看似正确的spring boot测试注解,仍然会遇到java.lang.nullpointerexception,提示@autowired的依赖对象为null,例如cannot invoke "com.company.restapi.dal.assignmentrepository.findall()" because "this.assignmentrepository" is null。
让我们通过一个具体的例子来理解这个问题。假设我们有一个AssignmentRepository接口,并为其编写了一个集成测试AssignmentRepositoryTest:
AssignmentRepository 接口代码:
@Repository
public interface AssignmentRepository extends CrudRepository<Assignment, Integer> {
List<Assignment> findAllByUserId(@NotNull(message = "No userId given") String userId);
}AssignmentRepositoryTest 测试类(存在问题版本):
import org.junit.Test; // <-- 注意这里的导入
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ActiveProfiles("test")
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = RestapiApplication.class, webEnvironment = SpringTest.WebEnvironment.RANDOM_PORT)
public class AssignmentRepositoryTest extends ContainerEnvironment { // 假设ContainerEnvironment是基础测试类
@Autowired
private AssignmentRepository assignmentRepository;
@Test // <-- 使用了JUnit 4的@Test注解
public void When_GetAssignments_Expect_EmptyList() {
List<Assignment> list = (List<Assignment>) assignmentRepository.findAll(); // 这里会抛出NullPointerException
assertEquals(0, list.size());
}
}在上述代码中,尽管我们使用了@SpringBootTest和@ExtendWith(SpringExtension.class)等Spring Boot测试相关的注解,但当执行When_GetAssignments_Expect_EmptyList方法时,assignmentRepository仍然是null,导致NullPointerException。
这个问题的核心在于@Test注解的导入。Spring Boot 2.x及更高版本默认集成了JUnit 5(也称为JUnit Jupiter)。JUnit 5引入了全新的扩展模型和注解体系,其中测试方法需要使用org.junit.jupiter.api.Test注解。
而代码中错误地导入了org.junit.Test,这是JUnit 4的@Test注解。当JUnit 5的测试运行器(由@ExtendWith(SpringExtension.class)指定)尝试执行测试时,它无法正确识别并处理JUnit 4的@Test注解标记的方法。这意味着,尽管Spring Boot的测试配置存在,但JUnit 5的测试运行器并没有将该方法识别为一个有效的JUnit 5测试方法,因此Spring的SpringExtension无法介入并初始化Spring应用上下文,也就无法执行@Autowired依赖注入。结果就是,assignmentRepository保持其默认的null值。
解决此问题的方法非常直接:将JUnit 4的@Test注解替换为JUnit 5的@Test注解。
修正后的AssignmentRepositoryTest 测试类:
import org.junit.jupiter.api.Test; // <-- 修正后的导入
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ActiveProfiles("test")
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = RestapiApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AssignmentRepositoryTest extends ContainerEnvironment {
@Autowired
private AssignmentRepository assignmentRepository;
@Test // <-- 现在使用的是JUnit 5的@Test注解
public void When_GetAssignments_Expect_EmptyList() {
// 当使用正确的@Test注解后,SpringExtension会正确初始化上下文,并注入assignmentRepository
List<Assignment> list = (List<Assignment>) assignmentRepository.findAll();
assertEquals(0, list.size());
}
}通过将import org.junit.Test;更改为import org.junit.jupiter.api.Test;,测试运行器现在能够正确识别并执行测试方法。@ExtendWith(SpringExtension.class)会确保Spring的测试上下文被正确加载和初始化,从而使得@Autowired注解能够成功地将AssignmentRepository实例注入到assignmentRepository字段中,解决了NullPointerException问题。
在Spring Boot集成测试中,@Autowired依赖为null的NullPointerException问题往往是一个看似复杂实则简单的陷阱。它的根本原因在于JUnit 4和JUnit 5的@Test注解混用。通过确保所有测试方法都使用org.junit.jupiter.api.Test注解,我们能够保证Spring测试上下文的正确初始化和依赖注入的顺利进行。理解并避免这种常见错误,将大大提高Spring Boot测试的效率和稳定性。
以上就是解决Spring Boot测试中@Autowired依赖为Null的常见陷阱的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号