Junit测试Controller时mock Service内部ClientCrm为空抛空指针异常
问题根因
你在进行Controller单元测试时的Mockito使用逻辑存在错误,导致mock失效、真实Service被调用触发空指针:
- 你已经用
@Mock标注了OfertasConcurrentesService,但又在@BeforeAll里手动执行ofertasService = new OfertasConcurrentesService();,直接把Mockito生成的mock实例覆盖成了真实对象 - 手动new的
OfertasConcurrentesService调用的是无参构造方法,没有传入ClientCrm实例,导致Service内部的clientCrm属性为null - 你测试的是Controller层,本来只要mock Service的返回结果即可,完全不需要初始化真实的Service实例,更不需要关心Service内部的Client依赖
修复方案
第一步:给测试类添加Mockito注解支持
在测试类上添加@ExtendWith(MockitoExtension.class)注解(Junit5对应Mockito的扩展),不需要手动初始化Controller和Service实例,Mockito会自动处理@Mock和@InjectMocks的注入逻辑。
第二步:删除@BeforeAll里的手动初始化代码
你手动编写的三行实例化代码完全覆盖了Mockito的注入逻辑,直接删除即可。
第三步:修正后的测试类示例
import org.mockito.junit.jupiter.MockitoExtension; import org.junit.jupiter.api.extension.ExtendWith; import java.util.Objects; @TestInstance(TestInstance.Lifecycle.PER_CLASS) @ExtendWith(MockitoExtension.class) // 新增Mockito扩展支持 class OfertaConcurrenteControllerTest { // 测试Controller不需要Mock ClientCrm,可以直接删除该行 // @Mock // private ClientCrm clientCrm; @Mock OfertasConcurrentesService ofertasService ; @InjectMocks OfertaConcurrenteController ofertasController; // 不需要@Autowired,测试时自己构造请求参数即可 OfertaRequest ofertaRequest; @Test void testPostOfertaAsync() throws Exception { List<Inmueble> listaInmuebles = new ArrayList<>(); listaInmuebles.add(new Inmueble("a","b","c","s","r","t","u")); Oferta oferta = new Oferta((long)266500000,LocalDateTime.of(2017, 2, 13, 15, 56),listaInmuebles); CompletableFuture<Oferta> futuro = CompletableFuture.completedFuture(oferta); ofertaRequest = new OfertaRequest("00457","087945","5642564z","4564","mail@mail.mail"); when(ofertasService.identificacionOferta(ofertaRequest)).thenReturn(futuro); // 可补充更具体的断言校验返回结果 CompletableFuture<ResponseEntity<Oferta>> result = ofertasController.postOfertaAsync(ofertaRequest); assert result != null; assert Objects.equals(result.get().getBody(), oferta); } @Test void testPropuestaCompra() { fail("Not yet implemented"); } }
额外说明
如果你后续需要单独测试Service层,再单独mock Service的依赖ClientCrm、EmailService等传入Service的构造方法即可,Controller层测试不需要关心Service内部的实现细节。
内容的提问来源于stack exchange,提问作者Alejandro Martin
相关产品推荐
相关产品推荐

