簡體   English   中英

在Spring 3.2.4中替代測試控制器

[英]Alternative to testing controllers in Spring 3.2.4

在Spring 3.0.5及之前的版本中,可以創建一個基本控制器測試類,該類從Spring Application Context中獲取HandlerMapping對象,以通過URL直接訪問並調用控制器的方法。 我發現這種方法確實很棒,因為除了測試控制器的方法外,我還在單元/集成測試中測試了路徑變量等。

在Spring 3.2.4中,由於重新構造了Spring處理Url映射的方式,這種方法似乎不再可行。 我看到Spring提供了一個新的MVC測試框架,但老實說,我認為它的設計過於冗長,看上去與框架的其余部分或我的應用程序代碼完全不同。 它也無法與IntelliJ中的智能感知功能配合使用。 老實說,我寧願不使用它。

那么,有沒有像我以前那樣不使用新的Spring MVC測試框架來測試控制器URL的替代方法? 我有一個具有371個控制器測試的現有項目,並且我真的很想避免遷移所有內容以使用Spring MVC測試框架。

這是我使用Spring 3.0.5來測試控制器的handle()方法:

protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    final HandlerMapping handlerMapping = applicationContext.getBean(HandlerMapping.class);
    final HandlerExecutionChain handler = handlerMapping.getHandler(request);
    assertNotNull("No handler found for request, check you request mapping", handler);

    final Object controller = handler.getHandler();

    final HandlerInterceptor[] interceptors = handlerMapping.getHandler(request).getInterceptors();

    for (HandlerInterceptor interceptor : interceptors) {
        final boolean carryOn = interceptor.preHandle(request, response, controller);
        if (!carryOn) {
            return null;
        }
    }

    return handlerAdapter.handle(request, response, controller);
}

protected ModelAndView handle(String method, String path, String queryString) throws Exception {
    request.setMethod(method);
    request.setRequestURI(path);

    if(queryString != null) {
        String[] parameters = queryString.split("&");
        for(String parameter : parameters) {
            String[] pair = parameter.split("=");
            if(pair.length == 2) {
                request.setParameter(pair[0], pair[1]);
            } else {
                request.setParameter(pair[0], "");
            }
        }
    }

    return handle(request, response);
}

protected ModelAndView handle(String method, String path, String attribute, Object object) throws Exception {
    MockHttpSession session = new MockHttpSession();
    session.setAttribute(attribute, object);
    request.setSession(session);

    return handle(method, path, null);
}

protected ModelAndView handle(String method, String path) throws Exception {
    return handle(method, path, null);
}

這是一些測試代碼,說明我如何使用handle()方法:

@Test
public void show() throws Exception {
    ModelAndView modelAndView = handle("GET", "/courseVersion/1/section/1");

    Section section = (Section) modelAndView.getModel().get("section");

    assertEquals(1, section.getId());
}

這是我的servlet應用程序上下文:

<?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"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations" value="classpath:applicationContext.properties"/>
    </bean>

    <bean id="expressionHandler"
          class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    </bean>

    <security:global-method-security pre-post-annotations="enabled">
        <security:expression-handler ref="expressionHandler"/>
    </security:global-method-security>

    <context:component-scan base-package="keiko.web.controllers"/>

    <mvc:annotation-driven validator="validator" />
    <mvc:interceptors>
        <bean class="keiko.web.interceptors.IpValidationInterceptor" />
        <bean class="keiko.web.interceptors.UnreadMessagesInterceptor" />
        <bean class="keiko.web.interceptors.ThemeInterceptor" />
        <bean class="keiko.web.interceptors.ApplicationMenuInterceptor" />
    </mvc:interceptors>

    <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
        <property name="freemarkerSettings">
            <props>
                <prop key="auto_import">lib/common.ftl as common, lib/layouts.ftl as layouts</prop>
                <prop key="whitespace_stripping">true</prop>
            </props>
        </property>
        <property name="freemarkerVariables">
            <map>
                <entry key="template_update_delay" value="0"/>
                <entry key="default_encoding" value="ISO-8859-1"/>
                <entry key="number_format" value="0.##"/>
                <entry key="xml_escape">
                    <bean class="freemarker.template.utility.XmlEscape"/>
                </entry>
            </map>
        </property>
    </bean>

    <bean id="contentNegotiatingViewResolver"
          class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1"/>
        <property name="ignoreAcceptHeader" value="true" />
        <property name="defaultContentType" value="text/html" />
        <property name="mediaTypes">
            <map>
                <entry key="html" value="text/html"/>
                <entry key="json" value="application/json"/>
            </map>
        </property>
        <property name="useNotAcceptableStatusCode" value="true" />
        <property name="viewResolvers">
            <list>
                <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
                    <property name="contentType" value="text/html" />
                    <property name="order" value="2"/>
                    <property name="cache" value="${freemarker.cache}"/>
                    <property name="prefix" value=""/>
                    <property name="suffix" value=".ftl"/>
                    <property name="exposeSpringMacroHelpers" value="true"/>
                </bean>
            </list>
        </property>
        <property name="defaultViews">
            <list>
                <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
                    <property name="contentType" value="application/json" />
                </bean>
            </list>
        </property>
    </bean>

    <bean id="viewNameTranslator" class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator"/>

    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="1000000"/>
    </bean>

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="keiko.domain.courseauthor.SectionIsDelayedException">error/sectionIsDelayed</prop>
                <prop key="keiko.service.director.CompanyHomepageClosedException">error/registrationClosed</prop>
                <prop key="keiko.service.director.IpDeniedException">error/ipDenied</prop>
            </props>
        </property>
    </bean>

</beans>

基本上,您的測試方法從一開始就存在缺陷。 總是有可能存在1個HandlerMapping和1個HandlerAdapter。 您基本上在做什么是模仿DispatcherServlet。

您應該做的是查找所有HandlerMappingHandlerAdapter並檢查它們中是否有一個與URL匹配(即返回HandlerExecutionChain),然后選擇適當的HandlerAdapter (調用supports方法)。 您要做的基本上就是DispatcherServlet所做的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM