JUnit 4.12单元测试遇NullPointerException,Service注入失败求助
问题分析与解决方案
问题根源
cartDetailsService 未被Mockito成功注入到 CartDetailsController 实例中,导致调用接口时触发 NullPointerException。同时原测试方法未Mock服务层返回值,即使注入成功也会返回null,无法通过断言检查。
修复步骤
1. 修正测试类的Mockito初始化方式
使用 @RunWith(MockitoJUnitRunner.class) 注解替代手动调用 MockitoAnnotations.initMocks(this),确保Mockito自动完成Mock实例的创建与注入,避免初始化时机问题。
2. Mock服务层返回值
在测试方法中指定 cartDetailsService.getCartDetails() 的返回结果,保证Controller调用后能得到预期响应。
3. 可选:为Controller添加Setter方法(增强测试友好性)
为 cartDetailsService 添加Setter,让Mockito注入更直观,也兼容更多场景。
修改后的代码
测试类代码
package com.convergeict.shoppingcartservice.controller; import com.convergeict.shoppingcartservice.model.CartDetails.CartSummary; import com.convergeict.shoppingcartservice.model.CartDetails.ChargeSummary; import com.convergeict.shoppingcartservice.response.GenericResponse; import com.convergeict.shoppingcartservice.service.CartDetailsService; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.http.ResponseEntity; import java.util.ArrayList; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) public class CartDetailsControllerTest { @InjectMocks private CartDetailsController cartDetailsController; @Mock private CartDetailsService cartDetailsService; @Test public void testGetCartDetailsSuccess() { String cartInstanceIdentifier = "937f4199-ef42-470a-8a35-719c39a3c064"; // 构造预期响应数据 CartSummary cartSummary = CartSummary.builder() .statusCode("0000") .statusDesc("Success") .totalChargeSummary(new ChargeSummary()) .cartItemSummaryList(new ArrayList<>()) .build(); GenericResponse<CartSummary> genericResponse = new GenericResponse<>(); genericResponse.setData(cartSummary); ResponseEntity<GenericResponse<?>> expectedResponse = ResponseEntity.ok(genericResponse); // Mock服务层方法返回值 when(cartDetailsService.getCartDetails(cartInstanceIdentifier)).thenReturn(expectedResponse); // 调用Controller接口 ResponseEntity<GenericResponse<?>> actualResponse = cartDetailsController.getCartDetails(cartInstanceIdentifier); // 验证结果 assertNotNull(actualResponse); assertEquals(expectedResponse.getStatusCode(), actualResponse.getStatusCode()); assertEquals(cartSummary, ((GenericResponse<CartSummary>) actualResponse.getBody()).getData()); verify(cartDetailsService, times(1)).getCartDetails(cartInstanceIdentifier); } }
Controller类代码(添加Setter可选)
@RestController @RequestMapping("/api") public class CartDetailsController { @Autowired private CartDetailsService cartDetailsService; // 测试友好的Setter方法 public void setCartDetailsService(CartDetailsService cartDetailsService) { this.cartDetailsService = cartDetailsService; } @RequestMapping(value = "/v1/cart-details", method = RequestMethod.GET) public ResponseEntity<GenericResponse<?>> getCartDetails(@RequestParam String cartInstanceIdentifier) { return cartDetailsService.getCartDetails(cartInstanceIdentifier); } }
关键说明
@RunWith(MockitoJUnitRunner.class)会在测试类初始化时自动处理@Mock和@InjectMocks的绑定,避免手动初始化可能出现的执行时机问题。- 必须通过
when(...).thenReturn(...)指定服务层方法的返回值,否则即使注入成功,Controller调用后也会返回null,无法通过断言检查。
内容的提问来源于stack exchange,提问作者drealmikaelson
相关产品推荐
相关产品推荐

