You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 10:52:19