I've been trying to figure out why my mocked findIngredientsByCategory method is returning null when I have when(controller.findIngredientsByCategory(any()).thenReturn(Collections.emptyList())
. This implementation works for the findAll method works.
Below is my implementation for my unit test:
@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);
}
And below is the implementation for the controller:
@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);
}
}
I'm not sure why the mock controller is returning null with this request, when I tell it to return an empty list. If someone could please help with this I would greatly appreciate it. Thanks.
The MockMvc
actually will call the IngredientController
that is bootstrapped and created by the Spring Test framework but not call the mocked IngredientController
that you annotated with @MockBean
, so all the stubbing that you made will not be called.
Actually, the point of @WebMvcTest
is to test @RestController
and its related Spring configuration is configured properly, so a real instance of IngredientController
is necessary to create rather than using a mocked one. Instead, you should mock the dependencies inside IngredientController
(ie IngredientRepository
).
So, the codes should looks like:
@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
}
}
use new ArrayList()
instead of Collections.emptyList()
when(controller.findIngredientsByCategory(any()).thenReturn(new ArrayList())
The core difference between
java.util.Collections.emptyList()
and a new list egnew ArrayList<>()
is immutability .
Collections.emptyList()
returns a list (java.util.Collections.EmptyList
) that can't be modified.
Remember,Collection.emptyList() creates a new empty list instance only once.
Th request path in test is "/ingredients/filter=meat", but it should be "/ingredients/filter?category=meat". So, it seem that getIngredientsByCategory
was not called.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.