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

JUnit测试cancelOrder抛出NullPointerException问题排查

问题根因

问题由测试代码编写疏漏+业务代码缺少鲁棒性校验共同导致,其中测试代码问题是触发本次空指针的直接原因。

测试代码问题

  • Mock注解未初始化:你使用@Mock标注了OrderDao,但没有启用Mockito注解处理,导致注入到OrderServiceImpl里的orderDao实际是null,调用orderDao.getById()时直接触发空指针。修复方式二选一:
    • 在测试类上添加JUnit5的Mockito扩展注解:@ExtendWith(MockitoExtension.class)
    • 在setUp()方法第一行添加MockitoAnnotations.openMocks(this);手动初始化Mock对象
  • Mock规则参数不匹配:你写的Mockito.when(orderDao.save(expectedResult)).thenReturn(expectedResult)要求入参必须是你提前new的expectedResult对象才会触发返回逻辑,但实际业务中传入save()的是修改了statusId后的mockOrder实例,和你new的expectedResult不是同一个对象,该Mock规则不会生效,save方法会返回Mock默认值null。
  • 断言逻辑不合理:业务逻辑中cancelOrder是修改查询到的原有订单对象的状态,不会生成新的Order实例,你提前new的expectedResult和实际方法返回的对象不是同一个实例,如果Order类没有重写equals()方法,哪怕字段值完全一致,assertEquals也会断言失败。

修正后的测试代码示例

@ExtendWith(MockitoExtension.class)
class OrderServiceImplTest {
    OrderServiceImpl orderService;

    @Mock
    OrderDao orderDao;

    @BeforeEach
    void setUp() {
        orderService = new OrderServiceImpl(orderDao);
    }

    @Test
    void cancelOrder() {
        Integer id = 1;
        // 初始状态为1,符合可取消条件
        Order mockOrder = new Order(1, 1, null, null, 1, null, 1);

        Mockito.when(orderDao.getById(id)).thenReturn(mockOrder);
        // 匹配任意Order类型入参,调用save时返回传入的参数本身
        Mockito.when(orderDao.save(Mockito.any(Order.class))).thenAnswer(invocation -> invocation.getArgument(0));

        Order actualResult = orderService.cancelOrder(id);
        
        // 断言返回订单状态已修改为5
        assertEquals(5, actualResult.getStatusId());
        // 断言DAO层的save方法确实被调用,且入参状态为5
        Mockito.verify(orderDao).save(Mockito.argThat(order -> order.getStatusId() == 5));
    }
}

业务代码可优化点

cancelOrder方法缺少空值校验,当传入不存在的订单ID时,orderDao.getById(id)会返回null,后续调用orderToCancel.getStatusId()会直接抛出空指针,建议补充非空判断:

@Override 
public Order cancelOrder(Integer id) {
    Order orderToCancel = this.orderDao.getById(id);
    // 补充订单不存在的校验
    if (orderToCancel == null) {
        // 可根据业务需求抛出业务异常或返回null
        return null;
    }
    if(orderToCancel.getStatusId() != 3 && orderToCancel.getStatusId() != 4){
        orderToCancel.setStatusId(5);
        return this.orderDao.save(orderToCancel);
    }
    return null;
}

内容的提问来源于stack exchange,提问作者mikal24

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 14:54:19