Spring Boot GraphQL测试上下文为空,测试用例无法执行
问题描述
我正在使用Spring Boot Test上下文、GraphQL测试与JUnit Jupiter框架测试GraphQL API端点,目标是验证从GraphQL获取数据的接口。但出现上下文加载后为空的问题,导致测试用例无法执行。以下是项目的pom文件与测试代码:
pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.espark.adarsh</groupId> <artifactId>sspringboot-graphql-crud-example</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot-graphql-crud-example</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-graphql</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.graphql</groupId> <artifactId>spring-graphql-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
测试文件
package com.espark.adarsh; import com.espark.adarsh.entity.Employee; import com.espark.adarsh.respository.EmployeeRepository; import com.espark.adarsh.service.EmployeeService; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest; import org.springframework.context.annotation.Import; import org.springframework.graphql.test.tester.GraphQlTester; import javax.annotation.PostConstruct; @GraphQlTest @Import({EmployeeService.class, EmployeeRepository.class}) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class EmployeeControllerTest { @Autowired EmployeeRepository employeeRepository; @Autowired EmployeeService employeeService; @Autowired GraphQlTester graphQlTester; @PostConstruct void init(){ employeeService.setEmployeeRepository(employeeRepository); } @Test @Order(1) void testGetAllEmployee(){ String document=""" query{ getAllEmployee{ id firstName lastName } } """; graphQlTester.document(document) .execute() .path("getAllEmployee") .entityList(Employee.class) .hasSize(4); } }
问题分析与解决方案
核心问题
@GraphQlTest是切片测试注解,默认仅加载GraphQL相关组件(如控制器、解析器),不会自动初始化Spring Data JPA的数据源、EntityManager等上下文。直接@ImportRepository和Service会导致依赖的JPA组件未被加载,最终出现空指针或上下文为空的问题。
修复方案
提供两种适配不同测试场景的方案:
方案一:完整上下文测试(适合真实数据库交互)
如果需要验证端到端的数据库查询逻辑,用@SpringBootTest替代@GraphQlTest,它会加载完整的Spring应用上下文,同时自动配置GraphQlTester:
@SpringBootTest @AutoConfigureGraphQlTester @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class EmployeeControllerTest { @Autowired EmployeeRepository employeeRepository; @Autowired EmployeeService employeeService; @Autowired GraphQlTester graphQlTester; // 每个测试前初始化测试数据,避免测试污染 @BeforeEach void init(){ employeeRepository.deleteAll(); employeeRepository.saveAll(Arrays.asList( new Employee(null, "Adarsh", "Kumar"), new Employee(null, "John", "Doe"), new Employee(null, "Jane", "Smith"), new Employee(null, "Mike", "Wilson") )); } @Test @Order(1) void testGetAllEmployee(){ String document=""" query{ getAllEmployee{ id firstName lastName } } """; graphQlTester.document(document) .execute() .path("getAllEmployee") .entityList(Employee.class) .hasSize(4); } }
方案二:Mock依赖测试(仅验证GraphQL解析逻辑)
如果只需要验证GraphQL接口的解析逻辑,不需要真实数据库交互,用@MockBean模拟业务层依赖:
@GraphQlTest(EmployeeController.class) // 指定要测试的GraphQL控制器/解析器 @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class EmployeeControllerTest { @Autowired GraphQlTester graphQlTester; @MockBean EmployeeService employeeService; @BeforeEach void init(){ // 模拟Service返回值 when(employeeService.getAllEmployee()).thenReturn(Arrays.asList( new Employee(1L, "Adarsh", "Kumar"), new Employee(2L, "John", "Doe"), new Employee(3L, "Jane", "Smith"), new Employee(4L, "Mike", "Wilson") )); } @Test @Order(1) void testGetAllEmployee(){ String document=""" query{ getAllEmployee{ id firstName lastName } } """; graphQlTester.document(document) .execute() .path("getAllEmployee") .entityList(Employee.class) .hasSize(4); } }
额外优化建议
- 替换手动注入方式:在
EmployeeService中使用构造函数注入,避免手动调用setEmployeeRepository:
@Service @RequiredArgsConstructor public class EmployeeService { private final EmployeeRepository employeeRepository; // 业务方法实现... }
- 用
@BeforeEach替代@PostConstruct:确保每个测试方法执行前都能重置数据,避免测试用例之间的污染。
内容的提问来源于stack exchange,提问作者Adarsh Kumar
相关产品推荐
相关产品推荐

