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

测试依赖UserInterface的RecipeService方法时遇空指针问题求助

问题描述

我有UserService和UserInterface,其中UserInterface包含返回固定用户的方法:

public User currentUser(){
  User user = new User();
  user.setId(1L);
  user.setName("Steve");
  return user;
}

另外还有RecipeService,其中的getRecipe方法是我要测试的对象。该方法会检查食谱创建者的用户ID是否与currentUser的ID一致,一致则返回食谱:

public Recipe getRecipe(Long id){
  User user = userInterface.currentUser();
  Recipe recipe = recipeRepository.findById(id);

  if(user.getId == recipe.getUser.getId()){
    return recipe;
  }
  
  return null;
}

我的测试代码如下:

class RecipeTest{
  
  @InjectMock private RecipeService recipeService;
  @Mock private RecipeRepository recipeRepository;
  @Mock private UserInterface userInterface;

  @BeforeEach
  void setUp(){
    recipeService = new RecipeService(userInterface);
  }
  
  @Test
  void getRecipe(){
    Recipe recipe = new Recipe();
    recipe.setId(1L);
    recipe.setTitle("SomeTitle");

    when(recipeRepository.findById(1L)).thenReturn(Optional.of(recipe))
    
    recipeService.getRecipe(1L);
    verify(recipeRepository).findById(1L);
  } 
}

启动测试时出现错误:getRecipe方法中调用UserInterface.currentUser()返回null,导致ID对比时触发空指针异常,看起来currentUser方法没有被正确调用。请问我哪里出错了?


问题原因与修复方案

你的测试代码存在几个关键问题,导致空指针异常:

  1. 未给Mock的UserInterface指定方法返回值
    你用@Mock创建了UserInterface的模拟对象,但没有通过when().thenReturn()定义currentUser()的返回结果,Mockito对Mock对象的未指定方法默认返回null。必须为这个方法设置模拟的用户返回值:

    // 在测试方法中添加这段代码
    User mockUser = new User();
    mockUser.setId(1L);
    when(userInterface.currentUser()).thenReturn(mockUser);
    
  2. 测试用Recipe未设置关联用户
    原方法需要对比recipe.getUser().getId(),但你创建的测试Recipe没有设置user属性,调用recipe.getUser()会返回null,同样触发空指针。需要给测试食谱绑定用户:

    Recipe recipe = new Recipe();
    recipe.setId(1L);
    recipe.setTitle("SomeTitle");
    // 添加关联用户,ID和Mock用户保持一致
    User recipeUser = new User();
    recipeUser.setId(1L);
    recipe.setUser(recipeUser);
    
  3. 混用@InjectMocks和手动实例化
    你既用@InjectMocks标注recipeService,又在setUp里手动new RecipeService(userInterface),这会导致Mockito的自动注入逻辑失效。建议统一方式:要么去掉手动实例化,依赖@InjectMocks自动注入所有Mock对象;要么保持手动实例化,去掉@InjectMocks注解。

  4. 原业务方法的语法错误
    注意到你原代码里的user.getId == recipe.getUser.getId()是错误的,Java调用方法需要加括号,正确写法是user.getId() == recipe.getUser().getId(),否则编译都无法通过,这也是潜在问题。

修复后的完整测试代码示例:

class RecipeTest{
  
  private RecipeService recipeService;
  @Mock private RecipeRepository recipeRepository;
  @Mock private UserInterface userInterface;

  @BeforeEach
  void setUp(){
    // 初始化Mockito的Mock对象
    MockitoAnnotations.openMocks(this);
    // 假设RecipeService构造方法需要同时传入userInterface和recipeRepository
    recipeService = new RecipeService(userInterface, recipeRepository);
  }
  
  @Test
  void getRecipe(){
    // 1. 准备Mock用户
    User mockUser = new User();
    mockUser.setId(1L);
    when(userInterface.currentUser()).thenReturn(mockUser);

    // 2. 准备测试用Recipe并设置关联用户
    User recipeUser = new User();
    recipeUser.setId(1L);
    Recipe recipe = new Recipe();
    recipe.setId(1L);
    recipe.setTitle("SomeTitle");
    recipe.setUser(recipeUser);

    // 3. Mock仓库返回值
    when(recipeRepository.findById(1L)).thenReturn(Optional.of(recipe));
    
    // 4. 执行测试方法
    Recipe result = recipeService.getRecipe(1L);
    
    // 5. 验证调用和结果
    verify(recipeRepository).findById(1L);
    assertNotNull(result);
    assertEquals("SomeTitle", result.getTitle());
  } 
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 23:55:11