by BehindJava

How to test RESTful Web Service (Controller) in Spring Framework Offline (No Server, No Database)

Home » java » How to test RESTful Web Service (Controller) in Spring Framework Offline (No Server, No Database)

In this tutorial, we will create a simple RESTful Controller that consumes and produces JSON and to test this controller without a server or database running. My initial test cases will include:

  • Test REST URIs, such as GET, POST, PUT, and DELETE - we must be able to Assert data returned against data sent.

Assert will validate JSON data we have in the below URIs:

  • /pcusers - Returns all users
  • /pcusers/id - Return a specific user
  • /pcusers/create/pcuser - Add user to database
  • /pcusers/update/pcuser - Update user
  • /pcusers/delete/id - Delete User

NOTE: This is NOT a typical MVC application. I HAVE NO POINTS OF VIEW. I have a pure REST controller that spits out JSON and consumes data in JSON format.

@Controller
@RequestMapping("/pcusers")
public class PcUserController {
    protected static Logger logger = Logger.getLogger(PcUserController.class);

    @Resource(name = "pcUserService")
    private PcUserService pcUserService;

    @RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json")
    @ResponseBody
    public List<PcUser> readAll() {
        logger.debug("Delegating to service to return all PcUsers");
        return pcUserService.readAll();
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET, consumes = "application/json", produces = "application/json")
    @ResponseBody
    public PcUser read(@PathVariable String id) {
        logger.debug("Delegating to service to return PcUser " + id);
        return pcUserService.read(id);
    }

    @RequestMapping(value = "/create/{pcUser}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
    @ResponseBody
    public boolean create(@PathVariable PcUser pcUser) {
        logger.debug("Delegating to service to create new PcUser");
        return pcUserService.create(pcUser);
    }

    @RequestMapping(value = "/update/{pcUser}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
    @ResponseBody
    public boolean update(@PathVariable PcUser pcUser) {
        logger.debug("Delegating to service to update existing PcUser");
        return pcUserService.update(pcUser);
    }

    @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
    @ResponseBody
    public boolean delete(@PathVariable String id) {
        logger.debug("Delegating to service to delete existing PcUser");
        return pcUserService.delete(id);
    }
}

Here is one thought that can help you come up with mocking better. You must be familiar with the @ContextConfiguration and the SpringJUnit4ClassRunner. Create a test application context first, including a mocked PcUserService and a PCUserController. Jackson is used to translate JSON messages in the example PcUserControllerTest class below, and Mockito is used for mocking.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(/* Insert test application context here */)
public class PcUserControllerTest {

    MockHttpServletRequest requestMock;
    MockHttpServletResponse responseMock;
    AnnotationMethodHandlerAdapter handlerAdapter;
    ObjectMapper mapper;
    PcUser pcUser;

    @Autowired
    PcUserController pcUserController;

    @Autowired
    PcUserService pcUserServiceMock;

    @Before
    public void setUp() {
        requestMock = new MockHttpServletRequest();
        requestMock.setContentType(MediaType.APPLICATION_JSON_VALUE);
        requestMock.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);

        responseMock = new MockHttpServletResponse();

        handlerAdapter = new AnnotationMethodHandlerAdapter();
        HttpMessageConverter[] messageConverters = {new MappingJacksonHttpMessageConverter()};
        handlerAdapter.setMessageConverters(messageConverters);

        mapper = new ObjectMapper();
        pcUser = new PcUser(...);

        reset(pcUserServiceMock);
    }
}

Now, we have all the intial setup done to create and run the tests.

@Test
public void shouldGetUser() throws Exception {
    requestMock.setMethod("GET");
    requestMock.setRequestURI("/pcusers/1");

    when(pcUserServiceMock.read(1)).thenReturn(pcUser);

    handlerAdapter.handle(requestMock, responseMock, pcUserController);

    assertThat(responseMock.getStatus(), is(HttpStatus.SC_OK));
    PcUser actualPcUser = mapper.readValue(responseMock.getContentAsString(), PcUser.class);
    assertThat(actualPcUser, is(pcUser));
}

@Test
public void shouldCreateUser() throws Exception {
    requestMock.setMethod("POST");
    requestMock.setRequestURI("/pcusers/create/1");
    String jsonPcUser = mapper.writeValueAsString(pcUser);
    requestMock.setContent(jsonPcUser.getBytes());

    handlerAdapter.handle(requestMock, responseMock, pcUserController);

    verify(pcUserServiceMock).create(pcUser);
}