How to write a unit test for a Spring Boot Control

2019-01-16 06:32发布

问题:

I have a sample Spring Boot app with the following

Boot main class

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

Controller

@RestController
@EnableAutoConfiguration
public class HelloWorld {
    @RequestMapping("/")
    String gethelloWorld() {
        return "Hello World!";
    }

}

What's the easiest way to write a unit test for the controller? I tried the following but it complains about failing to autowire WebApplicationContext

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = DemoApplication.class)
public class DemoApplicationTests {

    final String BASE_URL = "http://localhost:8080/";

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }

    @Test
    public void testSayHelloWorld() throws Exception{

         this.mockMvc.perform(get("/")
                 .accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
                 .andExpect(status().isOk())
                 .andExpect(content().contentType("application/json"));
    }

    @Test
    public void contextLoads() {
    }

}

回答1:

Spring MVC offers a standaloneSetup that supports testing relatively simple controllers, without the need of context.

Build a MockMvc by registering one or more @Controller's instances and configuring Spring MVC infrastructure programmatically. This allows full control over the instantiation and initialization of controllers, and their dependencies, similar to plain unit tests while also making it possible to test one controller at a time.

An example test for your controller can be something as simple as

public class DemoApplicationTests {

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = standaloneSetup(new HelloWorld()).build();
    }

    @Test
    public void testSayHelloWorld() throws Exception {
        this.mockMvc.perform(get("/").accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
                .andExpect(status().isOk())
                .andExpect(content().contentType("application/json"));

    }
}


回答2:

The new testing improvements that debuted in Spring Boot 1.4.M2 can help reduce the amount of code you need to write situation such as these.

The test would look like so:

import static org.springframework.test.web.servlet.request.MockMvcRequestB‌​uilders.get; 
import static org.springframework.test.web.servlet.result.MockMvcResultMat‌​chers.content; 
import static org.springframework.test.web.servlet.result.MockMvcResultMat‌​chers.status;

    @RunWith(SpringRunner.class)
    @WebMvcTest(HelloWorld.class)
    public class UserVehicleControllerTests {

        @Autowired
        private MockMvc mockMvc;

        @Test
        public void testSayHelloWorld() throws Exception {
            this.mockMvc.perform(get("/").accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
                    .andExpect(status().isOk())
                    .andExpect(content().contentType("application/json"));

        }

    }

See this blog post for more details as well as the documentation



回答3:

Here is another answer using Spring MVC's standaloneSetup. Using this way you can either autowire the controller class or Mock it.

    import static org.mockito.Mockito.mock;
    import static org.springframework.test.web.server.request.MockMvcRequestBuilders.get;
    import static org.springframework.test.web.server.result.MockMvcResultMatchers.content;
    import static org.springframework.test.web.server.result.MockMvcResultMatchers.status;

    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.http.MediaType;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.web.server.MockMvc;
    import org.springframework.test.web.server.setup.MockMvcBuilders;


    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class DemoApplicationTests {

        final String BASE_URL = "http://localhost:8080/";

        @Autowired
        private HelloWorld controllerToTest;

        private MockMvc mockMvc;

        @Before
        public void setup() {
            this.mockMvc = MockMvcBuilders.standaloneSetup(controllerToTest).build();
        }

        @Test
        public void testSayHelloWorld() throws Exception{
            //Mocking Controller
            controllerToTest = mock(HelloWorld.class);

             this.mockMvc.perform(get("/")
                     .accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
                     .andExpect(status().isOk())
                     .andExpect(content().mimeType(MediaType.APPLICATION_JSON));
        }

        @Test
        public void contextLoads() {
        }

    }


回答4:

Adding @WebAppConfiguration (org.springframework.test.context.web.WebAppConfiguration) annotation to your DemoApplicationTests class will work.