测试依赖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方法没有被正确调用。请问我哪里出错了?
你的测试代码存在几个关键问题,导致空指针异常:
未给Mock的
UserInterface指定方法返回值
你用@Mock创建了UserInterface的模拟对象,但没有通过when().thenReturn()定义currentUser()的返回结果,Mockito对Mock对象的未指定方法默认返回null。必须为这个方法设置模拟的用户返回值:// 在测试方法中添加这段代码 User mockUser = new User(); mockUser.setId(1L); when(userInterface.currentUser()).thenReturn(mockUser);测试用
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);混用
@InjectMocks和手动实例化
你既用@InjectMocks标注recipeService,又在setUp里手动new RecipeService(userInterface),这会导致Mockito的自动注入逻辑失效。建议统一方式:要么去掉手动实例化,依赖@InjectMocks自动注入所有Mock对象;要么保持手动实例化,去掉@InjectMocks注解。原业务方法的语法错误
注意到你原代码里的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

