将mock注入到Spring MockMvc WebApplicationContext中



我正在使用Spring-boot测试(通过JUnit4和Spring MockMvc)一个REST服务适配器。适配器只是将向它发出的请求传递给另一个REST服务(使用自定义RestTemplate),并向响应追加额外的数据。

我想运行MockMvc测试来执行控制器集成测试,但想用模拟覆盖控制器中的RestTemplate,以允许我预定义第三方REST响应并防止它在每次测试期间被击中。我已经能够通过实例化MockMvcBuilders.standAloneSetup()并将要测试的控制器与本文中列出的模拟注入(以及下面的设置)传递给它来实现这一点,但是我不能使用MockMvcBuilders.webAppContextSetup()做同样的事情。

我已经看过一些其他的帖子,没有一个回答这个问题,如何实现这一点。我希望使用实际的Spring应用程序上下文进行测试,而不是使用独立的上下文,以防止应用程序可能增长时出现任何间隙。

编辑:我正在使用Mockito作为我的mock框架,并试图将其中一个mock注入上下文中。如果这不是必要的,那就更好了。

控制器:

@RestController
@RequestMapping(Constants.REQUEST_MAPPING_PATH)
public class Controller{
    @Autowired
    private DataProvider dp;    
    @Autowired
    private RestTemplate template;
    @RequestMapping(value = Constants.REQUEST_MAPPING_RESOURCE, method = RequestMethod.GET)
    public Response getResponse(
            @RequestParam(required = true) String data,
            @RequestParam(required = false, defaultValue = "80") String minScore
            ) throws Exception {
        Response resp = new Response();
        // Set the request params from the client request
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put(Constants.PARAM_DATA, data);
        parameters.put(Constants.PARAM_FORMAT, Constants.PARAMS_FORMAT.JSON);
        resp = template.getForObject(Constants.RESTDATAPROVIDER_URL, Response.class, parameters);
        if(resp.getError() == null){
            resp.filterScoreLessThan(new BigDecimal(minScore));
            new DataHandler(dp).populateData(resp.getData());
        }
        return resp;
    }
}

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringApplicationConfiguration(classes = MainSpringBootAdapter.class)
@TestPropertySource("/application-junit.properties")
public class WacControllerTest {
    private static String controllerURL = Constants.REQUEST_MAPPING_PATH + Constants.REQUEST_MAPPING_RESOURCE + compressedParams_all;
    private static String compressedParams_all = "?data={data}&minScore={minScore}";
    @Autowired
    private WebApplicationContext wac;
    private MockMvc mockMvc;
    @InjectMocks
    private Controller Controller;
    @Mock
    private RestTemplate rt;
    @Value("${file}")
    private String file;
    @Spy
    private DataProvider dp;
    @Before
    public void setup() throws Exception {
        dp = new DataProvider(file);    
        MockitoAnnotations.initMocks(this);
        this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }
    @Test
    public void testGetResponse() throws Exception {
        String[] strings = {"requestData", "100"};
        Mockito.when(
            rt.getForObject(Mockito.<String> any(), Mockito.<Class<Object>> any(), Mockito.<Map<String, ?>> any()))
            .thenReturn(populateTestResponse());
        mockMvc.perform(get(controllerURL, strings)
            .accept(Constants.APPLICATION_JSON_UTF8))
            .andDo(MockMvcResultHandlers.print());
        Mockito.verify(rt, Mockito.times(1)).getForObject(Mockito.<String> any(), Mockito.<Class<?>> any(), Mockito.<Map<String, ?>> any());
        }

        private Response populateTestResponse() {
            Response  resp = new Response();
            resp.setScore(new BigDecimal(100));
            resp.setData("Some Data");
            return resp;
    }
}

Spring的MockRestServiceServer正是您正在寻找的。

类的javadoc简短描述:

客户端REST测试的主要入口点。用于直接或间接(通过客户端代码)使用RestTemplate的测试。提供了一种对将通过RestTemplate执行的请求设置细粒度期望的方法,并提供了一种定义要发回的响应的方法,从而消除了对实际运行的服务器的需要。

试着像这样设置你的测试:

@WebAppConfiguration
@ContextConfiguration(classes = {YourSpringConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class ExampleResourceTest {
    private MockMvc mockMvc;
    private MockRestServiceServer mockRestServiceServer;
    @Autowired
    private WebApplicationContext wac;
    @Autowired
    private RestOperations restOperations;
    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
        mockRestServiceServer = MockRestServiceServer.createServer((RestTemplate) restOperations);
    }

    @Test
    public void testMyApiCall() throws Exception {
        // Following line verifies that our code behind /api/my/endpoint made a REST PUT
        // with expected parameters to remote service successfully
        expectRestCallSuccess();
        this.mockMvc.perform(MockMvcRequestBuilders.get("/api/my/endpoint"))
            .andExpect(status().isOk());
    }
    private void expectRestCallSuccess() {
        mockRestServiceServer.expect(
            requestTo("http://remote.rest.service/api/resource"))
            .andExpect(method(PUT))
            .andRespond(withSuccess("{"message": "hello"}", APPLICATION_JSON));
    }

}

这是另一个解决方案。简单地说,它只是创建一个新的RestTemplate bean,并覆盖已经注册的那个。

因此,当它产生与@mzc answer相同的功能时,它允许我使用Mockito来更容易地制作响应和验证匹配器。

并不是说它不止几行代码,而是它还可以防止必须添加额外的代码来将Response对象转换为上述mockRestServiceServer.expect().andRespond(<String>)方法的参数的字符串。

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringApplicationConfiguration(classes = MainSpringBootAdapter.class)
@TestPropertySource("/application-junit.properties")
public class WacControllerTest {
    private static String Controller_URL = Constants.REQUEST_MAPPING_PATH + Constants.REQUEST_MAPPING_RESOURCE + compressedParams_all;
    @Configuration
        static class Config {
            @Bean
            @Primary
            public RestTemplate restTemplateMock() {
                return Mockito.mock(RestTemplate.class);
        }
    }
    @Autowired
    private WebApplicationContext wac;
    private MockMvc mockMvc;
    @InjectMocks
    private Controller Controller;
    @Mock
    private RestTemplate rt;
    @Value("${file}")
    private String file;
    @Spy
    private DataProvider dp;
    @Before
    public void setup() throws Exception {
        dp = new DataProvider(file); 
        MockitoAnnotations.initMocks(this);
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
        this.rt = (RestTemplate) this.wac.getBean("restTemplateMock");
    }
    @Test
    public void testGetResponse() throws Exception {
        String[] strings = {"request", "100"};
        //Set the request params from the client request
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put(Constants.PARAM_SINGLELINE, strings[0]);
        parameters.put(Constants.PARAM_FORMAT, Constants.PARAMS_FORMAT.JSON);
        Mockito.when(
            rt.getForObject(Mockito.<String> any(), Mockito.<Class<Object>> any(), Mockito.<Map<String, ?>> any()))
            .thenReturn(populateTestResponse());
        mockMvc.perform(get(Controller_URL, strings)
            .accept(Constants.APPLICATION_JSON_UTF8))
            .andDo(MockMvcResultHandlers.print());
        Mockito.verify(rt, Mockito.times(1)).getForObject(Mockito.<String> any(), Mockito.<Class<?>> any(), Mockito.<Map<String, ?>> any());
        }

        private Response populateTestResponse() {
            Response  resp = new Response();
            resp.setScore(new BigDecimal(100));
            resp.setData("Some Data");
            return resp;
    }
}

org.springframework.boot.test.mock.mockit。MockBean @MockBean帮了我的忙

相关内容

  • 没有找到相关文章

最新更新