MockMvc测试遇循环视图路径异常:默认视图解析器为何未生效?
核心原因:Standalone测试模式的默认视图解析逻辑和Web容器环境不一样
你碰到的这个问题,本质是**StandaloneMockMvcBuilder的默认视图解析行为,和实际Web容器(比如Tomcat)里的Spring MVC运行逻辑存在差异**。
先看你提到的API文档:StandaloneMockMvcBuilder的setViewResolvers方法说明“未设置视图解析器时,默认使用InternalResourceViewResolver”——但这里的“默认”有个容易被忽略的前提:它并不会像Web容器里那样自动带上JSP的前缀/后缀配置,而是用了一个极简的默认设置。
具体差异拆解
浏览器运行环境(Web容器):
在实际部署的Spring MVC应用中,你的InternalResourceViewResolver通常会在配置里指定前缀(比如/WEB-INF/views/)和后缀(比如.jsp)。所以当控制器返回视图名test时,会被解析成/WEB-INF/views/test.jsp,这是一个明确的JSP文件路径,和请求URL/test完全不冲突,因此浏览器访问正常。Standalone测试环境:
当你用standaloneSetup(controller).build()创建MockMvc时,默认的InternalResourceViewResolver是没有配置前缀和后缀的。这时候,视图名test会被直接当作请求路径处理,Spring MVC会尝试把请求转发到/test——而这恰好是你的TestController正在处理的URL,于是就触发了循环转发的异常:javax.servlet.ServletException: Circular view path [test]: would dispatch back to the current handler URL [/test] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
为什么setSingleView能解决问题?
你用setSingleView(new InternalResourceView("/WEB-INF/views/test.jsp"))的时候,相当于直接跳过了视图解析器的默认逻辑,硬指定了视图对应的物理文件路径,自然就不会出现循环转发的问题了。
更通用的解决方式(替代setSingleView)
如果不想硬编码单个视图,你可以手动给StandaloneMockMvcBuilder配置和实际应用一致的InternalResourceViewResolver,指定前缀和后缀:
MockMvc mockMvc = standaloneSetup(controller) .setViewResolvers(new InternalResourceViewResolver("/WEB-INF/views/", ".jsp")) .build();
这样视图名test就会被正确解析为/WEB-INF/views/test.jsp,测试就能正常通过,也更贴近实际运行环境的配置。
总结
StandaloneMockMvcBuilder确实会默认使用InternalResourceViewResolver,但它的默认配置是无前缀无后缀的“裸配置”,和Web容器中通常配置的解析器行为不同,这才导致了测试环境和实际运行环境的差异,进而出现循环视图路径的异常。
内容的提问来源于stack exchange,提问作者user6630815

