8

Spring-MVCWebアプリ用にSpring-Test-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またはそれが削除された場合、コンテンツはただ空になります。ただし、コントローラーが呼び出されるため、マッピングが機能する必要があります。

したがって、これは、ビューがテスト用にレンダリングされていないことを強く示唆していますが、どのセットアップが欠落している可能性があるのか​​わかりません。

これが私たちのservlet-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.springframework.web.context.support.GenericWebApplicationContext@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.springframework.beans.factory.support.DefaultListableBeanFactory@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.springframework.web.context.support.GenericWebApplicationContext@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.springframework.beans.factory.support.DefaultListableBeanFactory@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

だから私が問題を見つけるのを助けるどんな提案にも感謝します!

ところで:これがもう長くなりたくなかったので、私はpomをスキップしました。Spring 3.1、spring-test-mvc 1.0.0..BUILD-SNAPSHOT、jsp-ap 2.2、jstl 1.2、...を使用しています。詳細を知る必要がある場合は、どこかにアップロードしてみます...


編集

さらに詳しい情報が必要な場合、または私の質問に答えられない理由を教えてください。本当にそれを理解する必要があり、どこから始めればよいのかわかりません。ですから、どんな考えやコメントも歓迎します。


Edit2

次の出力でprintメソッドを使用しました。

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にはサーブレットコンテナが必要です。したがって、この方法でページをテストすることはできないようです...この問題を回避する方法を誰かが知っている場合は、私に知らせてください。

4

3 に答える 3

9

@Biju-私はこの答えに感謝し、それは私に旅行を節約しました、そして私はここでメッセンジャーを撃つことを試みていません、しかし私はもっと良いものを作るために動機づけられるかもしれないSpringチームの誰かの利益のために言わなければなりません、私MockMVCは、些細なことと無益なことの練習であることがわかりました。まず、Spring認証は直接サポートされていません。StackOverflowをスカウトすれば、その回避策を見つけることができます。それから私自身、Springコンテキスト構成を使用している場合、「notFound」を返す必要がある場合でも、作成できるすべてのパスが「OK」として返されることがわかりました。OK、何でも、それを取り出して、二度とそれについて話さないようにしましょう。:)そして今、MockMVCは実際にはMockMCだけであり、ビュー処理は行われないことがわかりました。

そして、これは実際には答えではありません、それは暴言です、それは今MockMVCが私にStackOverflowの評判も犠牲にすることを意味します!:) ハルクスマッシュ!

[編集]-OK暴言はさておき、これを回避する方法があるように見えます。[後の編集]残念ながら、私が見つけたこれを回避する方法はもう利用できません。

于 2014-01-20T18:40:57.673 に答える
1

edit3に追加すると、基本的にJSPレンダリングの場合、最後の呼び出しは次のようになります。

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

実装はRequestDispatcherコンテナによって提供されます(jspのコンパイル方法、コンパイルされたjspの配置場所などに依存するため)。RequestDispatcherのMock実装は、転送されたJSPページをキャプチャするだけであり、JSPへのパスが期待どおりであることを検証することしかできません。

于 2012-06-15T12:43:07.890 に答える
0

MockMvcと同じチェーンを構築し、転送要求のためにそのチェーンに要求を渡すMockRequestDispatcherの修正バージョンを作成しました。これでこの問題は解決しました。ビューがディスパッチャサーブレットの外部で(たとえば、jspを介して)レンダリングされる場合は、さらにいくつかの作業を行う必要があります。

コードはそこにあります:https ://gist.github.com/micw/a8b20720db900762a29d

ほとんどの作業は、適切な場所に注入することでした。これは、MockMvcのRequestPostProcessorと、MockHttpServletRequest.getRequestDispatcher呼び出しをインターセプトするmockito-magicを作成することで行いました。

これを使用するには、テストクラスパスに追加し、MockMvcインスタンスを作成した直後に呼び出します。

    mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
            [...]
            .build();
    WebMvcRequestDispatcherForwardFix.apply(mvc);
于 2015-09-17T10:25:35.850 に答える