在 Spring Boot 1.41 中结合 @WebMcvTest 和 @PathVariable 注释控制器

Combine @WebMcvTest with @PathVariable annotated controllers in Spring Boot 1.41

此问题的示例应用程序在这里:https://github.com/olemerdy-fa/webmvctest

我正在 bootstrapping 一个使用 Spring Boot 1.4.1 的新项目。我尝试利用这个伟大框架的新功能,尤其是对我的应用程序进行(相当)单元测试的能力 'slices'。

当我在 @Controller 上声明 @PathVariable 注释方法时,我现在对 @WebMvcTest 功能感到困惑。

事实上,@WebMvcTest 应该 bootstrap 一个控制器和 MockMvc 测试工具,而不提供任何其他东西。使用 @MockBean,提供模拟作为依赖项注入到此控制器中仍然很容易。

但是 @PathVariable 带注释的参数,其类型是,比如说,其转换器通常由 Spring Data 注册的 JPA 实体呢?

加入这个问题的示例项目包含几个示例:

失败并出现 org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException 异常

    2016-10-25 14:27:55.699  WARN 20753 --- [           main] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to convert request element: org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type [java.lang.String] to required type [com.Whosebug.MyEntity]; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.Whosebug.MyEntity]: no matching editors or conversion strategy found

    MockHttpServletRequest:
          HTTP Method = GET
          Request URI = /load2/123
           Parameters = {}
              Headers = {Accept=[application/json]}

    Handler:
                 Type = com.Whosebug.Webmvctest2Controller
               Method = public com.Whosebug.MyEntity com.Whosebug.Webmvctest2Controller.load2(com.Whosebug.MyEntity)

    Async:
        Async started = false
         Async result = null

    Resolved Exception:
                 Type = org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException

    ModelAndView:
            View name = null
                 View = null
                Model = null

    FlashMap:
           Attributes = null

    MockHttpServletResponse:
               Status = 500
        Error message = null
              Headers = {}
         Content type = null
                 Body =
        Forwarded URL = null
       Redirected URL = null
              Cookies = []
    Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.375 sec <<< FAILURE! - in com.Whosebug.Webmvctest2ControllerUnitTest
    load2(com.Whosebug.Webmvctest2ControllerUnitTest)  Time elapsed: 0.015 sec  <<< FAILURE!
    java.lang.AssertionError: Status expected:<200> but was:<500>
            at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54)
            at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:81)
            at org.springframework.test.web.servlet.result.StatusResultMatchers.match(StatusResultMatchers.java:664)
            at org.springframework.test.web.servlet.MockMvc.andExpect(MockMvc.java:171)
            at com.Whosebug.Webmvctest2ControllerUnitTest.load2(Webmvctest2ControllerUnitTest.java:28)

知道如何保留我的 @PathVariable 实体参数,同时仍然只用 @WebMvcTest 测试我的网络切片吗? 谢谢:)

感谢@zeroflagL 暗示对 HandlerMethodArgumentResolver 的可能贡献,我想出了一个似乎符合我需要的解决方案。贡献一个自定义转换器来处理控制器中的模拟实体注入似乎可以完成这项工作

    @RunWith(SpringRunner.class)
    @WebMvcTest(Webmvctest2Controller.class)
    public class Webmvctest2ControllerUnitTest {

        @Autowired
        private MockMvc mvc;

        @Test
        public void load2() throws Exception {
            mvc.perform(get("/load2/123").accept(MediaType.APPLICATION_JSON))
                    .andExpect(status().isOk())
                    .andExpect(content().json("{id:123,name:'My Entity'}"));
        }

        @TestConfiguration
        static class InternalConfig {

            @Bean
            WebMvcConfigurer configurer() {
                return new WebMvcConfigurerAdapter() {
                    @Override
                    public void addFormatters(FormatterRegistry registry) {
                        registry.addConverter(String.class, MyEntity.class, id -> {
                            if (id.equals("123")) {
                                MyEntity myEntity = new MyEntity(123);
                                myEntity.setName("My Entity");
                                return myEntity;
                            }
                            throw new IllegalArgumentException();
                        });
                    }
                };
            }
        }
    }

它并不完美,因为测试方法本身不能提供模拟实体,但它仍然允许我想保留的 web-unit-test bootstrap 和 运行。