CodeGym /Courses /Module 5. Spring /Summary of previous lectures

Summary of previous lectures

Module 5. Spring
Level 9 , Lesson 3
Available

We've finally reached controller testing. Controllers, as you know, handle HTTP requests and pass data between the client and the app's business logic. Everyone wants their controllers to work flawlessly, but someone has to check that. Spoiler: that's gonna be you. Luckily, we have a powerful tool — MockMvc.

Why test controllers? Well, first, controller testing makes sure your endpoints work (and not only in your browser).

Second, controllers are often the first part of the app that users blame when something breaks. For example, what will a user do if a request to URI /api/users returns a 500 Internal Server Error? Of course they'll blame your code (and maybe you personally). So if your code works, you're covered.


What is MockMvc?

MockMvc is a tool provided by Spring Test that lets you test web app behavior without deploying a real server. It simulates handling HTTP requests and lets you assert responses, headers, statuses, and even errors.

MockMvc lets you send test HTTP requests to your controllers and check how they respond. For example, you can send a GET request to /api/users and verify that the response status is 200 and the body contains the expected data.

Here's a small example of interacting with MockMvc:


mockMvc.perform(get("/api/users"))
    .andExpect(status().isOk())
    .andExpect(content().json("[{\"id\":1,\"name\":\"John Doe\"}]"));

Preparation for testing

Before you start writing tests, let's make sure we have everything we need:

  1. Controller: let's write a sample controller that we'll test.
  2. Dependencies: add Spring Boot Test, JUnit and Mockito for testing.
  3. MockMvc configuration: set up MockMvc for your tests.

Step 1: Example controller to test

Suppose we have a controller for working with users:


@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping
    public List<User> getAllUsers() {
        return userService.findAll();
    }

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User createdUser = userService.save(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }
}

The controller has two endpoints:

  • GET /api/users — returns a list of users.
  • POST /api/users — adds a new user.

Step 2: Setting up dependencies in pom.xml

Add the required dependencies for testing:


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <scope>test</scope>
</dependency>

Step 3: Writing tests for the controller

Now let's create a test class for UserController.

Import the required classes


import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

Set up the test class


@WebMvcTest(UserController.class)
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    // We'll write tests here
}

Step 4: Testing GET /api/users

Let's write a test to verify that GET /api/users returns the correct list of users.


@Test
public void shouldReturnListOfUsers() throws Exception {
    // Create test data
    List<User> users = List.of(new User(1L, "John Doe"), new User(2L, "Jane Doe"));

    // Configure mock behavior
    when(userService.findAll()).thenReturn(users);

    // Send GET request and verify the result
    mockMvc.perform(get("/api/users"))
           .andExpect(status().isOk())
           .andExpect(jsonPath("$.size()").value(users.size()))
           .andExpect(jsonPath("$[0].name").value("John Doe"))
           .andExpect(jsonPath("$[1].name").value("Jane Doe"));
}

What's happening here:

  1. Create a list of users for the test.
  2. Configure the userService mock to return that list when findAll() is called.
  3. Make a GET request to /api/users.
  4. Verify:
    • Response status (200 OK).
    • Size of the list in the JSON response.
    • Value of the name field for the users.

Step 5: Testing POST /api/users

Test that POST /api/users creates a new user.


@Test
public void shouldCreateNewUser() throws Exception {
    // Create a test user
    User newUser = new User(null, "John Doe");
    User savedUser = new User(1L, "John Doe");

    // Configure mock behavior
    when(userService.save(any(User.class))).thenReturn(savedUser);

    // Send POST request and verify the result
    mockMvc.perform(post("/api/users")
           .contentType(MediaType.APPLICATION_JSON)
           .content("{\"name\":\"John Doe\"}"))
           .andExpect(status().isCreated())
           .andExpect(jsonPath("$.id").value(1))
           .andExpect(jsonPath("$.name").value("John Doe"));
}

Here:

  1. We send a POST request with a JSON object.
  2. We check that:
    • The response status is 201 Created
    • The response contains the ID and name of the new user.

Useful tips

  1. Don't forget about edge cases: test not only positive scenarios but also negative ones. For example, what happens if you send invalid data.
  2. Use handy methods: MockMvc provides lots of useful methods like jsonPath(), header(), etc.
  3. Clean up after yourself: make sure your tests don't rely on state left by previous tests. Each test should be independent.

What's next?

Now you know how to test REST controllers using MockMvc. This not only helps ensure quality but also looks great on your resume. In the next lecture we'll focus on testing services and repositories. For now, arm yourself with this knowledge and go test your controllers!

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION