12

I have seen people around me using Spring MVC in unit tests for controller classes, which is not helpful in what a unit test is for.

Unit tests are supposed to test your actual implementation of the controller class, and this can be achieved more accurately with simple Junit tests rather than using Spring Mock MVC.

But then the question arises, what's the real usage of Spring Mock MVC then? What do you need it for?

Let's say I have below code :

@Controller
@RequestMapping("/systemusers")
public class SystemUserController
{
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String getUser(final Model model)
    {

        // some logic to return user's details as json

        return UserDetailsPage;
    }
 }

I can test this class/controller more accurately with Junit than with Spring Mock MVC (all it does is generates some json which can be asserted with junit).

I can also test with Spring Mock MVC like using the correct endpoint returns the correct HTTP status and correct response page string.

But doesn't that mean that we are testing Spring MVC's functionality rather than the actual code for method under test?

P.S. : I have kept the code to minimal which I think is sufficient to explain my question. Assume there is no compilation error.

Ghasem Sadeghi
  • 1,734
  • 13
  • 24
Abubakkar
  • 15,488
  • 8
  • 55
  • 83
  • 1
    The fact that something is written with JUnit doesn't mean it is a unit test it could very well be an integration test in which you wan to test the whole setup. – M. Deinum Mar 31 '17 at 10:21
  • The tests that I have seen are definitely not integration tests – Abubakkar Mar 31 '17 at 10:28
  • 4
    MockMvc can be used in 2 different ways, standalone and with a full blown setup. Standalone mode is basically setting up the controller and you execute it like you would with a request. Added advantage is that you are also testing your mappings on your controller, which you wouldn't be testing if you simply invoke the method. This might be very handy if you expect certain things to happen (type checking, custom error handling) . – M. Deinum Mar 31 '17 at 10:40
  • Next to that if you really need an extensive unit test to test functionality of your controller you are probably doing too much in your controller it should basically be nothing more then an integration component between the web and your service layer. It should contain little to no logic. – M. Deinum Mar 31 '17 at 10:41

2 Answers2

14

When it comes to the unit-testing of a Controller (or any Endpoint which is exposed) classes, there are two things that we will validate:

(1) Controller's actual logic itself as standalone i.e., right service calls are invoked or not etc..

(2) Request URL mapping and the Response status & object

(3) Input validation exceptions raised by Spring framework (when you use the @Valid)

Item (1) above is what we test in general with all other classes like Services, Utility classes etc..

Items (2) & (3) need to be covered/tested additionally for the endpoints (controller classes) which have been exposed, so whether we use Spring's MockMVC or other machinery to do that, it is up to us really.

Spring's MockMVC indeed helps us to start the in-memory servlet container & check that the right controller methods are invoked & then the right responses have been coming out.

From my personal experience, testing the controllers (for item(2)) helped me to resolve URL mapping conflict issues (of course, within the same controller) etc.. straight away rather than fixing them at the later stages of the project.

Vasu
  • 21,832
  • 11
  • 51
  • 67
  • 3
    add to that the possibility to test parameter validation with `@Valid` annotation and the corresponding return codes or the possibility to check that `@ExceptionHandler`s do their work. – P.J.Meisch Mar 31 '17 at 18:46
2

Based on My experience I will try to answer your question.

First thing we need to understand why we use unit testing?

It is a extra check used by developer to write clean working code. Clean working code means every line written should be doing what it is expected to do. how do you achieve this? Here comes unit testing. The standalone unit of code you are writing should be verified standalone. Method is best part in code which represents standalone unit code template.

Unit Testing for Method

Developer should write a test for method which describes the method behavior. And possible checks that i follow is is it returning the expected value considering all positive scenarios? is it working in case of Exception? is it calling correct subsequent methods ?

Developer should verify the method by actually calling it providing a mock environment

Below is possible answer to your question. though it is solely based upon the developers.

Controller methods are intended to invoke correct service call accepting input and returning the value from service to view. So I may think of write a unit test case for controller method as you are thinking is a right approach. But you should verify the method by calling it in same way as it will be called in real time. so you need to call controller method in same way as MVC does. Hence it is better option to use MockMVC. MockMVC is also useful to verify the urls, input params , response and status which are part of controller method. Considering these all it makes it standalone unit of code.

Hope this will clarify your doubt.

Dhiraj
  • 1,430
  • 11
  • 21