简体   繁体   English

使用 Spring mockMvc 测试可选路径变量

[英]Using Spring mockMvc to test optional path variables

I have a method in Spring MVC with optional path variable.我在 Spring MVC 中有一个带有可选路径变量的方法。 I am trying to test it for a scenario when optional path variable is not provided.我正在尝试针对未提供可选路径变量的场景对其进行测试。

Snippet from Controller, resource URI to invoke-来自控制器的片段,要调用的资源 URI-

@RequestMapping(value = "/some/uri/{foo}/{bar}", method = RequestMethod.PUT)
public <T> ResponseEntity<T> someMethod(
     @PathVariable("foo") String foo, 
     @PathVariable(value = "bar", required = false) String bar
) {
    LOGGER.info("foo: {}, bar: {}", foo, bar);
}

Snippet from my test using MockMvc-我使用 MockMvc 测试的片段-

//inject context
@Autowired
private WebApplicationContext webApplicationContext;

protected MockMvc mockMvc;

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

@Test
public void someMethodTest() throws Exception {
    //works as expected
    mockMvc.perform(put("/some/uri/{foo}/{bar}", "foo", "bar"))
            .andExpect(status().isOk()); //works

    //following doesn't work

    //pass null for optional
    mockMvc.perform(put("/some/uri/{foo}/{bar}", "foo", null))
            .andExpect(status().isOk()); //throws 404

    //pass empty for optional
    mockMvc.perform(put("/some/uri/{foo}/{bar}", "foo", ""))
            .andExpect(status().isOk()); //throws 404

    //remove optional from URI
    mockMvc.perform(put("/some/uri/{foo}", "foo"))
            .andExpect(status().isOk()); //throws 404
}

Using an array of @RequestMapping values like this ...使用像这样的@RequestMapping值数组...

@RequestMapping(
    value = {"/some/uri/{foo}", "/some/uri/{foo}/{bar}"}, 
    method = RequestMethod.PUT)
public ResponseEntity<String> someMethod(
    @PathVariable("foo") String foo, 
    @PathVariable(value = "bar", required = false) String bar
) {
    return new ResponseEntity<>(foo + " and " + (bar == null ? "<null>" : bar), HttpStatus.OK);
}

... will enable this test to pass: ...将使此测试通过:

@Test
public void someMethodTest() throws Exception {
    MvcResult mvcResult = mockMvc.perform(put("/some/uri/{foo}/{bar}", "foo", "bar"))
            .andExpect(status().isOk()).andReturn();
    Assert.assertEquals("foo and bar", mvcResult.getResponse().getContentAsString());

    mvcResult = mockMvc.perform(put("/some/uri/{foo}/{bar}", "foo", null))
            .andExpect(status().isOk()).andReturn();
    Assert.assertEquals("foo and <null>", mvcResult.getResponse().getContentAsString());

    mvcResult = mockMvc.perform(put("/some/uri/{foo}/{bar}", "foo", ""))
            .andExpect(status().isOk()).andReturn();
    Assert.assertEquals("foo and <null>", mvcResult.getResponse().getContentAsString());

    mvcResult = mockMvc.perform(put("/some/uri/{foo}", "foo"))
            .andExpect(status().isOk()).andReturn();
    Assert.assertEquals("foo and <null>", mvcResult.getResponse().getContentAsString());
}

That certainly seems to be the simplest solution and it is likely to be more friendly to tools such as Swagger since it make the mappings explicit.这当然似乎是最简单的解决方案,它可能对 Swagger 等工具更友好,因为它使映射变得明确。

However, you could also declare a wildcard mapping and then use a path matcher within your controller method to interpret the request URI.但是,您也可以声明通配符映射,然后在控制器方法中使用路径匹配器来解释请求 URI。 For example, this method ...比如这个方法...

private final AntPathMatcher antPathMatcher = new AntPathMatcher();

@RequestMapping(value = "/some/uri/with/wildcards/**", method = RequestMethod.PUT)
public ResponseEntity<String> someMethod(HttpServletRequest request) {
    String matched = antPathMatcher.extractPathWithinPattern(
            (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE), request.getPathInfo());
    // ugly parsing code to read the path variables, allowing for the optionality of the second one
    String foo = matched;
    String bar = null;
    String[] pathVariables = matched.split("/");
    if (pathVariables.length > 1) {
        foo = pathVariables[0];
        bar = pathVariables[1];
    }
    return new ResponseEntity<>(foo + " and " + (bar == null ? "<null>" : bar), HttpStatus.OK);
}

... will enable this test to pass: ...将使此测试通过:

@Test
public void someMethodTestWithWildcards() throws Exception {
    MvcResult mvcResult = mockMvc.perform(put("/some/uri/with/wildcards/{foo}/{bar}", "foo", "bar"))
            .andExpect(status().isOk()).andReturn();
    Assert.assertEquals("foo and bar", mvcResult.getResponse().getContentAsString());

    mvcResult = mockMvc.perform(put("/some/uri/with/wildcards/{foo}/{bar}", "foo", null))
            .andExpect(status().isOk()).andReturn();
    Assert.assertEquals("foo and <null>", mvcResult.getResponse().getContentAsString());

    mvcResult = mockMvc.perform(put("/some/uri/with/wildcards/{foo}/{bar}", "foo", ""))
            .andExpect(status().isOk()).andReturn();
    Assert.assertEquals("foo and <null>", mvcResult.getResponse().getContentAsString());

    mvcResult = mockMvc.perform(put("/some/uri/with/wildcards/{foo}", "foo"))
            .andExpect(status().isOk()).andReturn();
    Assert.assertEquals("foo and <null>", mvcResult.getResponse().getContentAsString());
}

This is late but I faced recently this situation and thought this post would help others.这已经很晚了,但我最近遇到了这种情况,并认为这篇文章会对其他人有所帮助。

In case of mocking endpoints with optional request param or path variable, you can specify it like this.如果使用可选的请求参数或路径变量模拟端点,您可以像这样指定它。

Say I have a method with params as m1(String param1, String param2) called from controller.假设我有一个从控制器调用的参数为m1(String param1, String param2)

Where param 2 is an optional param for controller, so at runtime null would be passed if it is not passed.其中 param 2 是控制器的可选参数,因此在运行时如果未传递 null 则将传递它。

How to mock:如何嘲讽:

Mockito.when(m1(Mockito.anyString(), Mockito.eq(null)).the return(<whatever you want to return>)

Use Mockito.eq(null) in your test to pass it as null for optional param.在测试中使用Mockito.eq(null)将其作为 null 传递给可选参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM