【问题标题】:Why aren't my Spring Controller's request mappings working inside of a mock WebApplicationContext?为什么我的 Spring Controller 的请求映射不能在模拟 WebApplicationContext 中工作?
【发布时间】:2015-09-28 17:30:43
【问题描述】:

我正在使用 Spring 文档 here。我的目标是使用“webAppContextSetup”选项来测试我的 spring 配置以及我的控制器,但是我无法将控制器的方法映射到 TestDispatcherServlet 中。到目前为止,我有以下设置:

数据配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <jpa:repositories base-package="com.example.test"/>

    <bean id="contractManagementDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="contractManagementDataSource"/>
        <!-- no need for the load time weaving from the spring documentation since we're using hibernate as our JPA provider -->
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/>

    <context:property-placeholder location="classpath:config.properties"/>

</beans>

MVC 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd

         http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.example.test"/>

    <mvc:annotation-driven />

    <mvc:resources mapping="/public/**" location="/public/"/>

    <mvc:view-controller path="/" view-name="contract-management"/>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

ContractController.java

@RestController
@RequestMapping("contract")
public class ContractController {
    @Autowired
    DaoService daoService;

    @RequestMapping("{name}")
    public Contract getContract(@PathVariable String name) {
        return daoService.findContract(name);
    }
}

ContractControllerIT.java

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("/spring/*.xml")
public class ContractControllerIT {
    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

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

    @Test
    public void getAccount() throws Exception {
        mockMvc.perform(get("contract/{name}", "test")).andExpect(status().isOk());
    }

}

目前我在运行测试时看到以下错误:

java.lang.AssertionError: Status expected:<200> but was:<404>

而且,有趣的是,失败前的一些看似矛盾的日志记录语句。

10:38:09.410 [main] INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [spring/mvc.xml]
10:38:09.469 [main] INFO  org.springframework.web.context.support.GenericWebApplicationContext - Refreshing org.springframework.web.context.support.GenericWebApplicationContext@7a4ccb53: startup date [Mon Sep 28 10:38:09 MDT 2015]; parent: org.springframework.web.context.support.GenericWebApplicationContext@4a22f9e2
10:38:09.607 [main] INFO  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/contract/{name}]}" onto public com.example.test.domain.Contract com.example.test.controller.ContractController.getContract(java.lang.String) throws java.lang.Exception
10:38:09.786 [main] INFO  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - Looking for @ControllerAdvice: org.springframework.web.context.support.GenericWebApplicationContext@7a4ccb53: startup date [Mon Sep 28 10:38:09 MDT 2015]; parent: org.springframework.web.context.support.GenericWebApplicationContext@4a22f9e2
10:38:09.813 [main] INFO  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - Looking for @ControllerAdvice: org.springframework.web.context.support.GenericWebApplicationContext@7a4ccb53: startup date [Mon Sep 28 10:38:09 MDT 2015]; parent: org.springframework.web.context.support.GenericWebApplicationContext@4a22f9e2
10:38:09.840 [main] INFO  org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped URL path [/public/**] onto handler 'org.springframework.web.servlet.resource.ResourceHttpRequestHandler#0'
10:38:09.844 [main] INFO  org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Root mapping to handler of type [class org.springframework.web.servlet.mvc.ParameterizableViewController]
10:38:09.889 [main] INFO  org.springframework.mock.web.MockServletContext - Initializing Spring FrameworkServlet ''
10:38:09.889 [main] INFO  org.springframework.test.web.servlet.TestDispatcherServlet - FrameworkServlet '': initialization started
10:38:09.898 [main] INFO  org.springframework.test.web.servlet.TestDispatcherServlet - FrameworkServlet '': initialization completed in 9 ms
10:38:09.912 [main] WARN  org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [contract/test] in DispatcherServlet with name ''

另外,这是我在 StackOverflow 上的第一个问题,因此欢迎和感谢任何有关如何改进我的问题的建议。

【问题讨论】:

  • 仅供参考:web.xml 与任何涉及 MockMvc 的讨论完全无关,因为 Spring MVC 测试框架在 Servlet 容器之外运行。
  • 我认为可能是这样,但我的目的是展示我如何分解我的配置文件以防出现问题。你认为我应该从问题中删除它吗?
  • 是的,我会删除 web.xml 列表,因为它只会让人感到困惑。

标签: java spring spring-mvc spring-test spring-test-mvc


【解决方案1】:
10:38:09.912 [main] WARN  org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [contract/test] in DispatcherServlet with name ''

最后一部分说明了一切:“合同/测试”没有映射,这是您在集成测试中执行 GET 请求的内容。

但是,控制器中的映射没有任何问题。唯一的问题是您在集成测试中省略了前导斜杠。

以下解决您的问题:

@Test
public void getAccount() throws Exception {
    mockMvc.perform(get("/contract/{name}", "test"))
           .andExpect(status().isOk());
}

特别注意"/contract/{name}"中的前导斜杠。

问候,

Sam(Spring TestContext 框架的作者

【讨论】:

  • 啊,我感觉问题可能是像这样的一些愚蠢的错误。感谢您花时间写出如此详尽的答案。
【解决方案2】:

我看到一些与我通常为控制器和测试所做的不同的事情:

ContractController.java - 为两个请求映射添加斜线:

@RequestMapping("/contract")
...
@RequestMapping("/{name}")

ContractControllerIT.java - 添加斜杠:

@Test
public void getAccount() throws Exception {
    mockMvc.perform(get("/contract/{name}", "test")).andExpect(status().isOk());
}

【讨论】:

  • 修复了它。我很想知道你发现了什么使这变得不必要。考虑到 spring 文档没有提到它,这绝对是一个令人沮丧的问题。
  • @jpack 我很高兴它有帮助。当文档不正确或遗漏某些内容时,这令人沮丧。我昨天尝试查找为什么需要服务器,但没有提出任何建议。由于没有回复,我今天打算删除此帖子。
  • 方案和服务器名称不是必需的。
  • 虽然建议在@RequestMapping 路径中使用前导斜杠以提高清晰度,但它们不是必需的。
  • @SamBranen 嘿,谢谢!我也在我的代码中更改了它。克隆存储库并使用他们的示例运行的危险之一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-25
  • 2017-10-24
  • 1970-01-01
  • 1970-01-01
  • 2013-02-03
  • 2012-08-23
相关资源
最近更新 更多