1. Introduction

In this tutorial, we'll show you how to test RestController in Spring. To test the controller, one of the most popular options is to use Mockito and MockMvc. In this example, we'll have two model classes, Cat and Sighting. So, the idea is to whenever Cat is spotted, one Sighting object is created that contains a reference to Cat and image of spotted cat. 

2. Maven dependencies

You'll only need spring-boot-starter-test artifact. 

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

3. Controller test

Here you'll see how to write two tests - one should test a situation where a list of returned sighting is empty, and we're just checking if we got 200 response code. Other will test situation when there's content in the Page. We'll mock service response by annotating it with @MockBean.

Since we're mocking response here, and response is Paginated, you'll also see here how to mock Page response:

Page<Sighting> sightingPageMockResponse = new PageImpl<Sighting>(new ArrayList<Sighting>());

Here's full code with two controller tests:

import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

import com.catspotservice.controller.SightingController;
import com.catspotservice.service.SightingService;
import com.model.catspot.Cat;
import com.model.catspot.Sighting;

@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest
public class SightingControllerTest {

	@Mock
	SightingController sightingController;

	@Autowired
	private MockMvc mockMvc;

	@MockBean
	private SightingService sightingService;

	Sighting sighting1;
	Sighting sighting2;
	List<Sighting> sightings;

	@Before
	public void createTestSightings() {
		Cat cat1 = new Cat();
		cat1.setId(1l);
		cat1.setName("black cat");
		cat1.setDescription("domestic black cat");
		cat1.setImage("location to some black cat image");
		Cat cat2 = new Cat();
		cat2.setId(2l);
		cat2.setName("orange cat");
		cat2.setDescription("some orange cat");
		cat2.setImage("path to some orange cat image");
		sighting1 = new Sighting();
		sighting1.setId(1l);
		sighting1.setCat(cat1);
		sighting2 = new Sighting();
		sighting2.setId(2l);
		sighting2.setCat(cat2);
		sighting2.setImage("some image2");
		sightings = new ArrayList<Sighting>();
		sightings.add(sighting1);
		sightings.add(sighting2);
	}

	@Test
	public void testGetSightings_ValidRequest_NoResponse() throws Exception {

		Page<Sighting> sightingPageMockResponse = new PageImpl<Sighting>(new ArrayList<Sighting>());
		when(sightingService.findSightings(1l, 1, 1)).thenReturn(sightingPageMockResponse);

		mockMvc.perform(
				MockMvcRequestBuilders.get("/api/public/sighting?catId=1&page=1&size=1").accept(MediaType.ALL))
				.andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
	}

	@Test
	public void testGetSightings_ValidRequest_PageResponse() throws Exception {
		Page<Sighting> sightingPageMockResponse = new PageImpl<Sighting>(sightings);
		when(sightingService.findSightings(1l, 1, 1)).thenReturn(sightingPageMockResponse);
		mockMvc.perform(MockMvcRequestBuilders.get("/api/public/sighting?catId=1&page=1&size=1")
				.accept(MediaType.ALL).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultHandlers.print())
				.andExpect(MockMvcResultMatchers.status().isOk()).andExpect(jsonPath("$.totalPages").value(1))
				.andExpect(jsonPath("$.totalElements").value(2)).andReturn();
	}
}

Notice that we annotated Test class with:

@Runner(SpringRunner.class)
@AutoConfigureSpringMvc
@SpringBootTest

To make MockMvc call some service use MockMvcRequestBuilders.httpMethod.

If you want to make MockMvc write response it got to the console use .andDo(MockMvcResultHandlers.print()) just before you start expecting params from the response.