Mockito when().thenReturn()应返回空列表,但却返回了null

3

我一直在试图弄清楚为什么我的模拟findIngredientsByCategory方法返回null,即使我有when(controller.findIngredientsByCategory(any()).thenReturn(Collections.emptyList())。这个实现对于findAll方法有效。

以下是我的单元测试实现:

@RunWith(SpringJUnit4ClassRunner.class)
@WebMvcTest(IngredientController.class)
@ContextConfiguration(classes = {TestContext.class, WebApplicationContext.class})
@WebAppConfiguration
public class IngredientControllerTest {

  @Autowired
  private WebApplicationContext context;

  @Autowired
  private MockMvc mvc;

  @MockBean
  private IngredientController ingredientController;

  @Before
  public void setup() {
    MockitoAnnotations.initMocks(this);
    mvc = MockMvcBuilders.webAppContextSetup(context).build();
  }

  @Autowired
  private ObjectMapper mapper;

  private static class Behavior {
    IngredientController ingredientController;

    public static Behavior set(IngredientController ingredientController) {
      Behavior behavior = new Behavior();
      behavior.ingredientController = ingredientController;
      return behavior;
    }

    public Behavior hasNoIngredients() {
      when(ingredientController.getAllIngredients()).thenReturn(Collections.emptyList());
      when(ingredientController.getIngredientsByCategory(any())).thenReturn(Collections.emptyList());
      when(ingredientController.getIngredientById(anyString())).thenReturn(Optional.empty());
      return this;
    }
  }

  @Test
  public void getIngredientsByCategoryNoIngredients() throws Exception {
    Behavior.set(ingredientController).hasNoIngredients();
    MvcResult result = mvc.perform(get("/ingredients/filter=meat"))
        .andExpect(status().isOk())
        .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
        .andReturn();
    String content = result.getResponse().getContentAsString();
    System.out.println(content);
 }

以下是控制器的实现:

@RestController
@RequestMapping("/ingredients")
public class IngredientController {

  @Autowired
  private IngredientRepository repository;

  @RequestMapping(value = "/filter", method = RequestMethod.GET)
  public List getIngredientsByCategory(@RequestParam("category") String category) {
    return repository.findByCategory(category);
  }
}

我不确定为什么模拟控制器在这个请求中返回null,当我告诉它返回一个空列表时。如果有人能帮忙解决这个问题,我将非常感激!谢谢。

2个回答

1
实际上,MockMvc将会调用由Spring测试框架引导和创建的IngredientController,而不是你用@MockBean注解的模拟IngredientController,因此你所做的所有存根都不会被调用。
实际上,@WebMvcTest的重点是测试配置正确的@RestController及其相关的Spring配置,因此需要创建一个真实的IngredientController实例,而不是使用模拟实例。相反,应该在IngredientController内部模拟依赖关系(即IngredientRepository)。
因此,代码应该如下所示:
@RunWith(SpringJUnit4ClassRunner.class)
@WebMvcTest(IngredientController.class)
@ContextConfiguration(classes = {TestContext.class, WebApplicationContext.class})
@WebAppConfiguration
public class IngredientControllerTest {

  @Autowired
  private WebApplicationContext context;

  @Autowired
  private MockMvc mvc;

  @MockBean
  private IngredientRepository ingredientRepository;


  @Test
  public void fooTest(){
    when(ingredientRepository.findByCategory(any()).thenReturn(Collections.emptyList())

    //And use the MockMvc to send a request to the controller, 
    //and then assert the returned MvcResult
  }

}

你如何使用这个实现来实例化控制器? - baron.jos
SpringJUnit4ClassRunner会启动Spring上下文,从而在幕后创建控制器。就像您通常启动Spring应用程序一样,您不需要自己创建控制器。 - Ken Chan
1
这对学习模拟的工作方式非常有帮助,所以谢谢! - baron.jos

1
测试中的请求路径是"/ingredients/filter=meat",但应该是"/ingredients/filter?category=meat"。因此,似乎没有调用getIngredientsByCategory

是的!问题已经解决了。谢谢!真不敢相信我居然错过了那个。 - baron.jos
无论如何,正如@ken-chan所提到的那样,这是一种奇怪的控制器方式。 - ilinykhma
是的,我现在明白了。谢谢大家。 - baron.jos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接