Java RestAPI测试报错:this.service为空无法调用PacienteService.findById
解决@WebMvcTest中Mock Service类为空的NullPointerException问题
测试Spring Boot编写的RestAPI时,使用@WebMvcTest测试PacienteController,启动测试后抛出空指针异常,错误信息如下:
java.lang.NullPointerException: Cannot invoke "com.tcc.tccbackend.services.PacienteService.findById(java.lang.Integer)" because "this.service" is null
测试代码
PacienteTest类:
@WebMvcTest(PacienteController.class) public class PacienteTest extends BaseTest { @Mock private PacienteService service; @Autowired private MockMvc mockMvc; @BeforeEach public void setup() { RestAssuredMockMvc.mockMvc(mockMvc); } @Test @DisplayName("Retorna sucesso quando busca um paciente ") public void t4() { Mockito.when(service.findById(9999)) .thenReturn(new Paciente(9999, "Gilberson", "gilber@gmail.com", "68211836104", "(67) 99625-5371", new Date(), List.of())); RestAssuredMockMvc .given() .header("Authorization", getJWT()) .accept(ContentType.JSON) .when() .get("/pacientes/9999") .then().statusCode(200); } }
BaseTest类:
public class BaseTest { public BaseTest(){ baseURI = "http://localhost"; port = 8080; basePath = "/api"; } public static String getJWT() { return given() .body("{\n" + "\t\"email\": \"paula@gmail.com\",\n" + "\t\"senha\": \"senha\"\n" + "}") .contentType(ContentType.JSON) .when() .post("/user/login") .then() .extract() .path("token"); } }
环境版本
- Java 17
- RestAssured 5.3.0
- SpringBoot 2.7.0
- SpringBoot Starter Test 2.7.0
- Junit 4.13.2
问题原因
@Mock注解仅由Mockito管理,不会自动注册到Spring容器中,而@WebMvcTest启动的测试上下文只会加载Controller及其依赖的Bean。此时Controller依赖的PacienteService没有被正确注入Mock实例,导致Controller中的service字段为空,调用方法时抛出NPE。
解决方案
方案1:使用@MockBean替代@Mock
@MockBean是Spring Boot提供的注解,会自动将Mock对象注册到Spring测试上下文,确保Controller能注入到这个Mock实例:
@WebMvcTest(PacienteController.class) public class PacienteTest extends BaseTest { // 将@Mock替换为@MockBean @MockBean private PacienteService service; @Autowired private MockMvc mockMvc; @BeforeEach public void setup() { RestAssuredMockMvc.mockMvc(mockMvc); } // 测试方法不变 }
方案2:手动初始化Mockito注解(保留@Mock)
在@BeforeEach方法中调用MockitoAnnotations.openMocks(this),手动初始化所有标注@Mock的字段:
@WebMvcTest(PacienteController.class) public class PacienteTest extends BaseTest { @Mock private PacienteService service; @Autowired private MockMvc mockMvc; @BeforeEach public void setup() { // 初始化Mock对象 MockitoAnnotations.openMocks(this); RestAssuredMockMvc.mockMvc(mockMvc); } // 测试方法不变 }
额外注意事项
当前BaseTest中的getJWT()方法直接调用真实的登录接口,这不符合单元测试的隔离原则(@WebMvcTest仅启动Controller层,不会加载完整服务)。建议:
- 使用
@MockBeanMock用户认证相关的Service,让getJWT()返回固定的测试Token - 若使用Spring Security,可添加
@WithMockUser注解跳过真实权限验证
内容的提问来源于stack exchange,提问作者Victor
相关产品推荐
相关产品推荐

