Spring-Test-MVC / MockServletContext - содержимое пустое в тесте, но работает на Tomcat

Мы пытаемся настроить Spring-Test-MVC для нашего веб-приложения Spring-MVC. Мы начали использовать freemarker, и все было хорошо. Мы решили против этого и сейчас пытаемся настроить его с помощью JSP. Когда тестовое приложение развернуто на Tomcat, оно работает. Когда мы запускаем простой тест:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = WebContextLoader.class, locations = { "file:src/main/webapp/WEB-INF/servlet-context.xml" })
public class SkelletonTest {

    @Inject
    private MockMvc mockMvc;

    @Test
    public void homeTest() throws Exception {
        mockMvc.perform(get("/")).andExpect(status().isOk())
                .andExpect(content().type("text/html;charset=ISO-8859-1"))
                .andExpect(content().string(containsString("Hello World!")));
    }

это говорит:content type not set или если это будет удалено, содержимое будет просто пустым. Однако будет вызван контроллер, поэтому отображение должно работать.

Таким образом, это настоятельно предполагает, что представление не отображается для наших тестов, но я понятия не имею, какую настройку я могу пропустить.

Вот наш сервлет-context.xml:

<context:component-scan base-package="package.to.controllers" />
<mvc:annotation-driven />

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass"
        value="org.springframework.web.servlet.view.JstlView" />
    <property name="exposeContextBeansAsAttributes" value="true" />
    <property name="prefix" value="/views/" />
    <property name="suffix" value=".jsp" />
</bean>

WebContextLoader:

public class WebContextLoader extends GenericWebContextLoader {
    public WebContextLoader() {
        super("src/main/webapp", false);
    }
}

GenericWebContextLoader это оригинал Spring-Test-MVC.

MockMvc настраивается как Bean-компонент следующим образом:

@Configuration
public class TestConfig {

    @Inject
    private WebApplicationContext wac;

    @Bean   
    public MockMvc create(){
        return (MockMvcBuilders.webApplicationContextSetup(this.wac).build());
    }
}

Так что это настройка. web.xml не используется тестовой средой и не должен иметь значения, как это было раньше.

Я думаю, что должна быть дополнительная настройка в контексте сервлета. Он загружен, что я проверил, но в то время как для развернутого приложения Tomcat это имеет значение, то, что я установил для префикса и суффикса, оно просто проигнорирует тест.

Не уверен, насколько поможет трассировка ошибок, но вот она:

java.lang.AssertionError: Content type not set
    at org.springframework.test.web.AssertionErrors.fail(AssertionErrors.java:35)
    at org.springframework.test.web.AssertionErrors.assertTrue(AssertionErrors.java:57)
    at org.springframework.test.web.server.result.ContentResultMatchers$1.match(ContentResultMatchers.java:59)
    at org.springframework.test.web.server.MockMvc$1.andExpect(MockMvc.java:84)
    at our.package.SkelletonTest.homeTest(SkelletonTest.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

И тестовый вывод:

2012-06-15 10:41:04 TestContextManager [INFO] @TestExecutionListeners is not present for class [class package.to.test.SkelletonTest]: using defaults.
2012-06-15 10:41:05 XmlBeanDefinitionReader [INFO] Loading XML bean definitions from URL [file:src/main/webapp/WEB-INF/servlet-context.xml]
2012-06-15 10:41:05 ClassPathBeanDefinitionScanner [INFO] JSR-330 'javax.inject.Named' annotation found and supported for component scanning
2012-06-15 10:41:05 GenericWebApplicationContext [INFO] Refreshing org.s[email protected]158539f: startup date [Fri Jun 15 10:41:05 CEST 2012]; root of context hierarchy
2012-06-15 10:41:05 AutowiredAnnotationBeanPostProcessor [INFO] JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2012-06-15 10:41:05 DefaultListableBeanFactory [INFO] Pre-instantiating singletons in org.s[email protected]c64bc2: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,testConfig,freemarkerController,homeController,tableService,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0,org.springframework.format.support.FormattingConversionServiceFactoryBean#0,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0,org.springframework.web.servlet.handler.MappedInterceptor#0,org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0,org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0,org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0,org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,viewResolver,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,create]; root of factory hierarchy
2012-06-15 10:41:05 RequestMappingHandlerMapping [INFO] Mapped "{[/],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.ModelAndView package.to.controller.HomeController.index()
2012-06-15 10:41:05 RequestMappingHandlerMapping [INFO] Mapped "{[/test],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String package.to.controller.HomeController.test(org.springframework.ui.Model)
2012-06-15 10:41:06 GenericWebContextLoader$1 [INFO] Initializing Spring FrameworkServlet ''
2012-06-15 10:41:06 TestDispatcherServlet [INFO] FrameworkServlet '': initialization started
2012-06-15 10:41:06 TestDispatcherServlet [INFO] FrameworkServlet '': initialization completed in 32 ms
2012-06-15 10:41:06 GenericWebApplicationContext [INFO] Closing org.s[email protected]158539f: startup date [Fri Jun 15 10:41:05 CEST 2012]; root of context hierarchy
2012-06-15 10:41:06 DefaultListableBeanFactory [INFO] Destroying singletons in org.s[email protected]c64bc2: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,testConfig,freemarkerController,homeController,tableService,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0,org.springframework.format.support.FormattingConversionServiceFactoryBean#0,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0,org.springframework.web.servlet.handler.MappedInterceptor#0,org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0,org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0,org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0,org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,viewResolver,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,create]; root of factory hierarchy

Так что спасибо за любые предложения, которые помогут мне найти проблему!

Кстати: я не хотел, чтобы это продолжалось, поэтому я пропустил пом. Мы используем Spring 3.1, spring-test-mvc 1.0.0..BUILD-SNAPSHOT, jsp-ap 2.2, jstl 1.2, ... Если вам нужно узнать больше, я попытаюсь загрузить его куда-нибудь ...

Edit

Пожалуйста, дайте мне знать, если вам нужна дополнительная информация или почему вы не можете ответить на мой вопрос. Очень нужно разобраться, и я понятия не имею, с чего начать. Так что любые мысли или комментарии тоже приветствуются.

Edit2

Использовал метод печати со следующим выводом:

MockHttpServletRequest:
         HTTP Method = GET
         Request URI = /
          Parameters = {}
             Headers = {}

             Handler:
                Type = package.to.controller.HomeController
              Method = public org.springframework.web.servlet.ModelAndView package.to.controller.HomeController.index()

  Resolved Exception:
                Type = null

        ModelAndView:
           View name = index
                View = null
           Attribute = welcome
               value = Hello World!

            FlashMap:

MockHttpServletResponse:
              Status = 200
       Error message = null
             Headers = {}
        Content type = null
                Body = 
       Forwarded URL = /views/index.jsp
      Redirected URL = null
             Cookies = []

Который просто показывает проблему лучше, но не решение ...

edit3

Просто выяснил следующее:

JSP требует контейнер сервлета. Похоже, я не могу проверить свои страницы таким образом ... Если у кого-то есть идеи, как обойти эту проблему, пожалуйста, дайте мне знать ...

Ответы на вопрос(3)

которая создает ту же цепочку, что и MockMvc, и передает запрос в эту цепочку для пересылки запросов. Это решает эту проблему для меня. Еще немного работы нужно выполнить, если представление отображается вне сервлета диспетчера (например, через jsp).

Код там есть:https://gist.github.com/micw/a8b20720db900762a29d

Большая часть работы заключалась в том, чтобы ввести его в нужном месте. Я сделал это, создав RequestPostProcessor для MockMvc и некоторую магию mockito, которая перехватывает вызов MockHttpServletRequest.getRequestDispatcher.

Чтобы использовать его, добавьте его в свой тестовый путь к классам и вызовите его сразу после создания экземпляра MockMvc:

    mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
            [...]
            .build();
    WebMvcRequestDispatcherForwardFix.apply(mvc);
Решение Вопроса

по существу, для рендеринга JSP, последний вызов

RequestDispatcher requestDispatcher = httpRequest.getRequestDispacher(jspPath)
requestDispatcher.forward(httpRequest,httpResponse)

иRequestDispatcher реализации обеспечиваются контейнером (поскольку это зависит от того, как должны компилироваться jsp, где размещать скомпилированные jsp и т. д.). Mock-реализация RequestDispatcher просто захватывает перенаправленную страницу JSP, и выcan only validate that the path to the JSP is what you expect it to be.

@Biju - я ценю этот ответ, и он спас меня от поездки, и я не пытаюсь застрелить мессенджера здесь, но я должен сказать, что в интересах любого из команды Spring, который может быть заинтересован в создании чего-то лучшего, я Я считаю, что MockMVC - упражнение в тривиальности и тщетности.. Хорошо, если вы разыскиваете StackOverflow, вы можете найти обходной путь к этому. Затем я обнаружил, что, если у вас есть в вашей весенней контекстной конфигурации, каждый путь, который вы можете придумать, возвращается как "OK" даже если он должен вернуть «notFound». Хорошо, что угодно, возьми это и позволь нам никогда больше об этом не говорить. :) А теперь узнайте, что MockMVC - это действительно только MockMC - обработка представления не происходит. Итак, в конце концов, это программное обеспечение хорошо подходит для тестирования приложений, которые не содержат ни безопасности, ни представлений - что будет, в точности, игрушечные приложения JSON?

И это не совсем ответ, это напыщенная речь, что означает, что теперь MockMVC будет стоить мне репутации StackOverflow! :) Халк разбить!

[РЕДАКТИРОВАТЬ] - ОК, разглагольствовать в сторону, похоже, есть способы обойти это. [ПОСЛЕДНЕЕ РЕДАКТИРОВАНИЕ] К сожалению, путь, который я нашел, больше не доступен.

 29 июл. 2015 г., 17:03
В то время как это была напыщенная речь, это была также полезная напыщенная речь, вероятно, только сэкономила мне 2 часа, поскольку Вы так изящно выразились"scout StackOverflow"
 06 авг. 2015 г., 16:04
@ dwjohnston - да, сейчас так и есть, но не тогда, когда я это поднимаю. В любом случае я удалил ссылку.
 04 июн. 2016 г., 16:18
Какой был способ обойти это? Может ли это работать снова сейчас? Я & APOS; мhaving the same problem.
 05 июн. 2016 г., 17:40
На самом деле, я обнаружил, что он действительно отображает представление, если вы действительно загружаете конфигурацию представления (сначала я этого не делал). Очевидно, это не работает для представлений JSP, но меня интересуют только XML и JSON.
 05 авг. 2015 г., 06:27
Ах ... эта ссылка на сайт сексуального спама.

Ваш ответ на вопрос