当前位置: 首页 > 知识库问答 >
问题:

将模拟注入Spring MockMvc WebApplication ationContext

田慈
2023-03-14

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

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

我已经阅读了其他一些文章,没有一个回答了如何实现的问题。我想在测试中使用实际的Spring应用程序上下文,而不是独立的上下文,以防止应用程序可能增长时出现任何空白。

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

控制器:

@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;
    }
}

共有3个答案

计泉
2023-03-14

组织。springframework。靴子测验嘲弄莫基托。MockBean@MockBean帮了我一把。

南门承教
2023-03-14

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

因此,虽然它执行产生与@mzc答案相同的功能,但它允许我使用Mockito更轻松地制作响应和验证匹配器。

并不是说它不仅仅是几行代码,但它也防止了必须添加额外的代码来将响应对象转换为上述mockRestServiceServer.expect(). andResond(

@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;
    }
}

梁丘缪文
2023-03-14

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));
    }


}
 类似资料:
  • 问题内容: 我想将Mockito模拟对象注入到Spring(3+)bean中,以进行JUnit的单元测试。我的bean依赖项当前是通过在私有成员字段上使用注释来注入的。 我考虑过使用,但是我希望注入的bean实例实际上是一个代理,因此没有声明目标类的私有成员字段。我不希望为依赖项创建一个公共的setter,因为我将纯粹出于测试目的而修改接口。 我遵循了Spring社区提供的一些建议,但是未创建该模

  • 问题内容: 我写了一个AngularJS服务,我想对其进行单元测试。 我的app.js文件已注册: 我可以测试DI是否像这样工作: 这证明了可以通过DI框架创建服务,但是接下来我要对服务进行单元测试,这意味着要模拟注入的对象。 我该怎么做呢? 我试过将我的模拟对象放在模块中,例如 并将服务定义重写为: 但是后者似乎停止了DI所创建的所有服务。 有人知道我可以如何为单元测试模拟注入的服务吗? 谢谢

  • 问题内容: 我有以下代码: 我想使用Mockito创建一个测试。我编写了如下测试: 我在网上收到NullPointerException: ,它表示“策略”列表已初始化,但为空。Mohito有什么办法可以像Spring一样浪费时间?是否将所有实现接口“策略”的实例自动添加到列表中? 顺便说一句,我在Wrapper类中没有任何二传手,如果可能的话,我想以这种方式离开。 问题答案: Mockito不知

  • 我们有一些传统的laravel项目,它们在类中使用正面。 我们最近的项目使用了底层laravel类的依赖注入,facades所代表的类正如Taylor Otwell自己所暗示的那样。(我们对每个类使用构造函数注入,但为了保持示例简短,这里我使用方法注入并使用单个类。) 我知道外表是可以被嘲笑的 这对单元测试很有效。我试图理解的问题是,这些门面是否被“全球”嘲笑。 例如,让我们假设我正在编写一个集成

  • spring日志中的info消息显示: 示例: 下面有一个简单的示例,可以使用。这里,Bar是嵌套在Foo内部的,我需要模拟Bar进行测试: 现在对于测试来说,假设我想注入一个mockbar而不是真正的bar。我如何在下面的测试类中实现这一点? 实际测试用例:

  • 目前,我遇到了一些莫基托图书馆的麻烦...更确切地说,我无法将userRepository bean注入到我的模拟服务中。对于依赖注入,我使用的是spring boot。下面是一些代码示例: 在我的测试方法中,我想在用户得到更新之前跳过验证和令牌创建。 因此,当我调用updateUser方法时,问题出现在我的测试方法中,它失败了,因为我的userRepository没有注入(NullPointer