【问题标题】:Spring Boot - MockMVC forwardedUrl using ThymeleafSpring Boot - 使用 Thymeleaf 的 MockMVC forwardedUrl
【发布时间】:2017-10-01 21:54:26
【问题描述】:

我有一个基本的 SpringBoot 应用程序。使用 Spring Initializer、嵌入式 Tomcat、Thymeleaf 模板引擎,并打包为可执行 JAR 文件。

我有这个控制器:

@Controller
@RequestMapping("/deviceevent")
public class DeviceEventController {

    @RequestMapping(value={ "/list"}, method = { RequestMethod.GET})
    public String deviceeventList()  {

        return "tdk/deviceEvent/DeviceEventList";
    }
}

还有这个其他的测试类。使用 Spring 的 MockMVC 框架进行测试。这会在测试中驱动 MVC 应用程序,就像它在容器中运行一样,

    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @WebMvcTest
    public class MockMvcTests {

        // Pull in the application context created by @ContextConfiguration
        @Autowired
        private WebApplicationContext wac;

        private MockMvc mockMvc;

        @Before
        public void setup() {
            // Setup MockMVC to use our Spring Configuration
            this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
        }


        @Test
        public void getDeviceEventsTest() throws Exception {
            this.mockMvc
                    .perform(get("/deviceevent/list") //
                            .accept(MediaType.parseMediaType("text/html;charset=UTF-8")))
                    .andExpect(status().isOk()) //
                    .andExpect(model().size(1)) //
.andExpect(forwardedUrl("tdk/deviceEvent/DeviceEventList"));
        }

但我在转发的 URL 中收到此错误。我一直在 JSP 中使用这种方法,从来没有在 Thymeleaf 中使用过,但我猜它是一样的:

 java.lang.AssertionError: Forwarded URL expected:</tdk/deviceEvent/DeviceEventList> but was:<null>

【问题讨论】:

  • 你能提供你的 HTML 代码吗,我认为在传递对象时你得到空值

标签: spring-mvc spring-boot thymeleaf junit4 mockmvc


【解决方案1】:

假设一个标准的 Thymeleaf/Spring 设置,看起来对控制器正在做的事情存在误解 - 当控制器返回该字符串 "tdk/deviceEvent/DeviceEventList" 时,它不是在某处转发 HTTP 请求,而是返回一个视图名称。

使用正常的 Spring-thymeleaf 设置,该字符串对应于将在到达该端点时呈现的 thymeleaf 视图的名称(我假设控制器只是为普通网页提供服务-因此该路径可能对应于某个文件路径最有可能在src/main/resources - 但同样,这在很大程度上取决于您的 Spring 配置) - 此时 HTTP 请求尚未返回给用户,Spring 仍在处理它 - 并将尝试在之前呈现 HTML 视图返回给用户。

如果 Spring 不呈现任何内容,而是使用 301/302 机制向用户返回 HTTP 响应以将它们转发到另一个 URL(这将启动不同的 Spring 请求-响应过程),则使用转发的 URL。

注意以下方法的区别:

@RequestMapping( value="/document", method=RequestMethod.GET )
public String newDocumentSettings( Model model ){
    model.addAllAttributes( contentManagementService.documentToJson() );
    return "pages/document-settings";
}


@RequestMapping( value="/document", method=RequestMethod.POST )
public String createNewDocument( @RequestParam String title, @RequestParam String overview, @RequestParam String tags ){
    Document doc = documentService.createDocument( title, overview, tags );
    return "redirect:/document/${doc.url}/1?getting-started";
}

第一个在给定的文件路径处呈现模板,第二个向浏览器返回重定向命令以向给定的 URL 发出另一个 HTTP 请求。

无论如何,您的测试用例中的forwardedUrl 是因为hte HTTP 响应没有要转发到的URL(因为它返回了HTML)。如果您确实想要转发行为(例如,您实际上想要完成响应并且浏览器发出第二个 HTTP 请求),那么您可能需要按照示例更新控制器,但是,如果您对呈现的 html 页面感到满意,那么测试无效(查看 Thymeleaf 测试框架以了解如何测试模板)。

警告:这是基于默认 Spring-Boot 配置的假设 - 如果您有其他配置,该字符串确实会导致转发 HTTP 请求,那么这不适用!

【讨论】:

    【解决方案2】:

    在这里猜测一下,但 URL tdk/deviceEvent/DeviceEventList 可能没有定义。尝试将其替换为与您的上下文关联的 URL(根据需要进行编辑):

        @Test
        public void getDeviceEventsTest() throws Exception {
            this.mockMvc
                    .perform(get("/deviceevent/list")
                            .accept(MediaType.parseMediaType("text/html;charset=UTF-8")))
                    .andExpect(status().isOk()) 
                    .andExpect(model().size(1))
                    .andExpect(forwardedUrl("/WEB-INF/tdk/deviceEvent/DeviceEventList.html"));
        }
    

    除此之外,而不是:

    @RequestMapping(value={ "/list"}, method = { RequestMethod.GET})

    你可以使用简写:

    @GetMapping("/list")

    【讨论】:

      猜你喜欢
      • 2015-01-01
      • 2017-06-28
      • 2019-08-05
      • 2017-05-26
      • 2019-06-28
      • 2019-07-22
      • 1970-01-01
      • 2017-08-26
      • 2020-12-18
      相关资源
      最近更新 更多