Spring 引导 - 使用 Thymeleaf 的 MockMVC forwardedUrl

Spring Boot - MockMVC forwardedUrl using Thymeleaf

我有一个基本的 Spring 启动应用程序。使用 Spring 初始化程序,嵌入 Tomcat,Thymeleaf 模板引擎,并打包为可执行 JAR 文件。

我有这个控制器:

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

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

        return "tdk/deviceEvent/DeviceEventList";
    }
}

和另一个测试 class。使用 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>

这里猜测一下,但是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})

您可以使用 shorthand:

@GetMapping("/list")

假设一个标准的 Thymeleaf/Spring 设置,看起来控制器在做什么存在误解 - 当控制器 returns 那个字符串 "tdk/deviceEvent/DeviceEventList" 它没有转发 HTTP在某处请求,但返回视图名称。

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

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

注意以下方法的区别:

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

第一个在给定的文件路径处呈现模板,第二个 returns 一个重定向命令到浏览器以向给定的 URL.

发出另一个 HTTP 请求

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

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