I'm writing integration tests for a spring web app and I have reached a step where I need to mock service methods calls which have a void return type. I've done some research on some ways to do this but none seem to be the correct way. Below I'll provide the code and also the two main ways I've tried already. If anyone can help that would be great!
The method that needs mocking
@RequestMapping(path = "/recipes/add", method = RequestMethod.POST)
public String persistRecipe(@Valid Recipe recipe, BindingResult result, @RequestParam("image") MultipartFile photo, RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
redirectAttributes.addFlashAttribute("recipe", recipe);
redirectAttributes.addFlashAttribute("flash",
new FlashMessage("I think you missed something. Try again!", FlashMessage.Status.FAILURE));
return "redirect:/recipes/add";
}
User user = getUser();
recipe.setOwner(user);
user.addFavorite(recipe);
recipeService.save(recipe, photo);
userService.save(user);
redirectAttributes.addFlashAttribute("flash", new FlashMessage("The recipe has successfully been created", FlashMessage.Status.SUCCESS));
return "redirect:/recipes";
}
The service that needs calling (save method)
@Service
public class RecipeServiceImpl implements RecipeService {
private final RecipeRepository recipes;
@Autowired
public RecipeServiceImpl(RecipeRepository recipes) {
this.recipes = recipes;
}
@Override
public void save(Recipe recipe, byte[] photo) {
recipe.setPhoto(photo);
recipes.save(recipe);
}
@Override
public void save(Recipe recipe, MultipartFile photo) {
try {
recipe.setPhoto(photo.getBytes());
recipes.save(recipe);
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Recipe findById(Long id) {
Optional<Recipe> recipe = recipes.findById(id);
if (recipe.isPresent()) {
return recipe.get();
}
// TODO:drt - Create new exception to handle this
throw new RuntimeException();
}
@Override
public Recipe findByName(String name) {
return null;
}
@Override
public List<Recipe> findAll() {
return (List<Recipe>) recipes.findAll();
}
@Override
public void deleteById(Long id) {
recipes.deleteById(id);
}
}
Attempt 1
@Test
@WithMockUser(value = "daniel")
public void createNewRecipeRedirects() throws Exception {
User user = userBuilder();
Recipe recipe = recipeBuilder(1L);
recipe.setOwner(user);
user.addFavorite(recipe);
MockMultipartFile photo = new MockMultipartFile("image", "food.jpeg",
"image/png", "test image".getBytes());
when(userService.findByUsername("daniel")).thenReturn(user);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) {
Recipe recipe1 = (Recipe) arguments[0];
MultipartFile file = (MultipartFile) arguments[1];
recipe1.setPhoto(file.getBytes());
}
return null;
}
}).when(recipeService).save(any(Recipe.class), any(MultipartFile.class));
mockMvc.perform(post("/recipes/add"))
.andExpect(redirectedUrl("/recipes"))
.andExpect(flash().attributeExists("flash"));
}
Attempt 2
@Test
@WithMockUser(value = "daniel")
public void createNewRecipeRedirects() throws Exception {
List<Recipe> recipes = recipeListBuilder();
List<User> users = new ArrayList<>();
User user = userBuilder();
Recipe recipe = recipeBuilder(1L);
recipe.setOwner(user);
user.addFavorite(recipe);
MockMultipartFile photo = new MockMultipartFile("image", "food.jpeg",
"image/png", "test image".getBytes());
when(userService.findByUsername("daniel")).thenReturn(user);
doAnswer(answer -> {
recipe.setPhoto(photo.getBytes());
recipes.add(recipe);
return true;
}).when(recipeService).save(any(Recipe.class), any(MultipartFile.class));
doAnswer(answer -> {
users.add(user);
return true;
}).when(userService).save(any(User.class));
mockMvc.perform(post("/recipes/add"))
.andExpect(redirectedUrl("/recipes"))
.andExpect(flash().attributeExists("flash"));
assertEquals(3, recipes.size());
assertEquals(1, users.size());
}
Aucun commentaire:
Enregistrer un commentaire