Level 7 - Milestone 13

Milestone 13 - Integration Testing the Home Controller

In this section we will add an integration test for our HomeController method.

Before completion of this milestone, students will:

  • Learn how to write a basic integration test.

Creating a Class for the Integration Test

Add a HomeControllerIntTest class inside the appropriate folder within the IntTest source set, keep in mind that the structure reflects the structure of our main and test source sets.

Using @WebMvcTest

With our integration tests, we will issue a "fake" request to our application, and check to see that Spring invokes the correct method when a request is made to a certain endpoint. Notice how this differs from our unit tests: in our unit tests we used an instance of an object to invoke a method directly, and check that it returned the expected result. Here, we are taking a step back and checking that when a request is issued to a certain URL, that Spring and the code that we wrote end up doing the correct thing.

Because we are testing that the application responds correctly to a request, rather than a single method in isolation, we need to bring up the Spring part of the application to conduct these tests. It is because we need to run the application as a whole for our integration tests, that integrations test take much long to run that unit tests.

In order to launch Spring for our integration test, we need another annotation: @WebMcvTest. This will be added right about the class definition for our HomeControllerIntTest. This annotation auto-configures the Spring MVC infrastructure and the MockMVC (that will discuss shortly) for use with our tests. In our integration tests, we aren't going to mention any classes specifically, as we rely on Spring to test the mapping between a given URL and the method that is called, but we can improve our @WebMvcTest annotation to make our tests a little more efficient. Instead of having our integration test bring up the entire Spring context for our application, we can give it a "hint" as to which slice of the application is needed for this tests. This will allow us to only start up the slice of the application that is under tests here, making it run much more quickly. We can update the class annotation to "@WebMvcTest(HomeController.class)" to accomplish this.

Adding MockMvc Dependency to the Class

In preparation for the next step, add a "private MockMvc mockMvc" field to the class, with an @Autowired annotation above it so that it is automatically instantiated.

Adding the Integration Test Method

The basis of the test method will look just as it does in the unit tests. In this case, something like the following would be appropriate:

@Test
public void whenHome_ThenReturnMovedPermanentlyAndRedirect() {

}

Completing the Test Method

We will use the MockMvc we created previously to execute the integration test. In general, the structure of the test will be somewhat similar to our unit tests: we will execute something, and then tests that the result is what we expected. For our integration tests, however, the syntax for will be considerable different since we are using this MockMvc to issue a request instead of calling a method directly. In the case of our HomeController method, we want to test that when a request is sent to the root URL, "/", that two things occur. First, that an "Move Permanently" status code is returned, and second that the String that redirects our use to our swagger page is sent. We will also print our some additional things. This makes it easy to see what went wrong in the even that our test fails. The code that executes this is pretty readable, and reproduced here:

@Test
public void givenController_WhenHome_ThenReturnMovedPermanentlyAndRedirect() throws Exception {
    mockMvc.perform(get("/"))
        .andDo(print())
        .andExpect(status().isMovedPermanently())
        .andExpect(redirectedUrl("swagger-ui.html"));
}

Run the Test

At this point our test is complete. You should be able to run it and see that it passes. Remember that at this point there are multiple ways for you to run your tests. You can run it using one of the play buttons in the IDE gutter, or use the the Gradle "intTest" or "check" tasks.

Summary of Code Changes for this Milestone

    Cheetah-Search
    • src
      • intTest
      • main
        • java
          • org.jointheleague.level7.cheetah
            • config
              • ApiDocConfig.java
            • presentation
              • HomeController.java
              • LocController.java
            • service
              • LocService.java
            • repository
              • dto
                • Result.java
                • LocResponse.java
              • LocRepository.java
          • resources
            • application.yml
      • test
        • java
          • org.jointheleague.level7.cheetah
            • presentation
              • HomeControllerTest.java
              • LocControllerTest.java
            • service
              • LocServiceTest.java
            • repository
              • LocRepositoryTest.java
    • build.gradle