Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial
Alexey Papin
iOS Development Techdegree Graduate 26,950 PointsRedirectAttributes and Tests
I need test my controller method. Code of controller:
@RequestMapping(path="/add", method = RequestMethod.POST) public RedirectView addToCart(@ModelAttribute(value="productId") long productId, @ModelAttribute(value="quantity") int quantity, RedirectAttributes redirectAttributes) throws ProductNotFoundException {
RedirectView redirect = new RedirectView("/product/"); redirect.setExposeModelAttributes(false);
try { redirectAttributes.addFlashAttribute("flash", shoppingCartService.addQuantity(sCart, productId, quantity)); } catch (ExceedsProductQuantityException e) { e.printStackTrace(); redirectAttributes.addFlashAttribute("flash", new FlashMessage(e.getMessage(), FlashMessage.Status.FAILURE)); }
return redirect; }
My test code looks like:
@Test(expected = ExceedsProductQuantityException.class) public void addTooManyToCartTest1() throws Exception { Product product = productBuilder(); product.setQuantity(15);
Purchase purchase = purchaseBuilder(product); // First purchase
when(productService.findById(1L)).thenReturn(product);
when(sCart.getPurchase()).thenReturn(purchase);
mockMvc.perform(MockMvcRequestBuilders.post("/cart/add")
.param("quantity", String.valueOf(product.getQuantity() + 1))
.param("productId", "1"))
.andExpect(MockMvcResultMatchers.model().attribute("flash", "rdValue"))
.andExpect(MockMvcResultMatchers.flash().attribute("flash", FlashMessage.class));
}
But I get NestedServledException error message, I think its because in my controller method I try to work with RedirectedAttributes, but it's null. So, where and how I have to init and set RedirectedAttributes in my test?
4 Answers
Alexander Nikiforov
Java Web Development Techdegree Graduate 22,175 PointsI looked at your code. No offence taken. But you put a bit too much on Service Layer... Anyway... Coming back to your error. In your Controller method you use shoppingCartService.addQuantity(...). When you use service in testing you have to @Autowire it. I added
@Mock
private ShoppingCartService shoppingCartService;
And that changed error to normal Assertion error. Try that out. And remember that everything you @Autowire in controller has to be @Mock -ed in Testing.
Alexander Nikiforov
Java Web Development Techdegree Graduate 22,175 PointsIt is a very bad idea to use
try..catchblock in @RequestMapping Controller method. Use @ExceptionHandler method: Did you watch "Unit Testing in Spring"? There isFavoriteController.notFoundexample: https://github.com/treehouse-projects/spring-unit-test-weather/blob/master/src/main/java/com/teamtreehouse/web/controller/FavoriteController.javaUse
doPrintmethod, to see what exactly your request looks like, There are a lot of tests like this in our project, it will help you.About the Error. It is highly likely that there is something other wrong. Redirect Attributes if they are null. You will get Unit Test Assertion Error, not ServletException - which is more severe.
To see what exactly the problem is share link to your GitHub project. Then Anyone can take a look, Otherwise the structure of the project is too complicated to make judgement of Error, just by couple of lines that you've shown.
Alexander Nikiforov
Java Web Development Techdegree Graduate 22,175 PointsI'm following 'Spring Unit Testing' Structure of App, considering @ExceptionHandler:
- Exception is checked and thrown in Service Layer: see
findByIdmethod here, e.g. https://github.com/treehouse-projects/spring-unit-test-weather/blob/master/src/main/java/com/teamtreehouse/service/FavoriteServiceImpl.java - In the controller nothing happens: You just execute service method, like
detailmethod here: https://github.com/treehouse-projects/spring-unit-test-weather/blob/master/src/main/java/com/teamtreehouse/web/controller/FavoriteController.java - When exception happens, @ExceptionHandler
notFoundmethod takes care of what to do after. In case ofFavoriteNotFoundExceptionerror page is generated.
About your question what is view range for @ExceptionHandler? I mean do I have to write copy of it for each class/package?... I don't really understand what you mean. Exception is usually defined in separate package, like
com.teamtreehouse.exception. When it is thrown in controller method, @ExceptionHandler method checks all the methods for exceptions specified in @Exception(SomeException.class) annotation argument. Important thing is to add Exception exception to arguments of the @ExceptionHandler method. Take a look at the links above. When you do that you can access Exception thrown in the body of your @ExceptionHandler method. Again take a look how it is done. Also nice theoretical introduction in Spring Docs, if you need:
https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
Alexey Papin
iOS Development Techdegree Graduate 26,950 PointsI've asked about case when same exception (like in my case) thrown in differrent controllers (ProductNotFoundException thrown in ProductController, CartController and even in CheckoutController), so question was have I to rewrite same @ExceptionHandler in differrent controllers (since they are in diff classes/files?) Thanks for your help anyway. And we can speak russian :)
Alexander Nikiforov
Java Web Development Techdegree Graduate 22,175 PointsYes, I think you have to rewrite @ExceptionHandler in each controller, I guess, because controllers are not linked in any ways. I'm sure there probably is the way to generalize @ExceptionHandler for all controllers, but I don't know it. I don't know the rules about language here, so lets leave it english :) Glad that can be of some help.
Alexey Papin
iOS Development Techdegree Graduate 26,950 PointsAlexey Papin
iOS Development Techdegree Graduate 26,950 PointsYep, you right. Found that error yesterday :). Rewrite @ExceptionHandler right now, what is view range for @ExceptionHandler? I mean do I have to write copy of it for each class/package?