如何阻止其他JUnit测试窃取我的Spring Root Controller?

时间:2016-03-18 23:13:40

标签: java spring unit-testing spring-mvc junit

我有一个看起来像这样的JUnit测试 - 它是一个更大的应用程序的一部分。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = { MyTestConfig.class })
public class MyHandlerInterceptorTest  {

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Test
    public void myTest() throws Exception {
        MockHttpServletRequest request = new MockHttpServletRequest("GET",
            "/myrequest");
        HandlerExecutionChain handlerExecutionChain = requestMappingHandlerMapping.getHandler(request);
    }
}

当我单独运行我的测试时 - 它运行正常。

当我将其作为一系列其他测试的一部分运行时 - 我收到错误

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.MyHandlerInterceptorTest  ': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping com.MyHandlerInterceptorTest.requestMappingHandlerMapping; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration: Initialization of bean failed; nested exception is org.springframework.context.ApplicationContextException: Cannot reinitialize with different application context: current one is [Root WebApplicationContext: startup date [XXX 2016]; root of context hierarchy], passed-in one is [org.springframework.context.support.GenericApplicationContext@4760457f: startup date [XXX 2016]; root of context hierarchy]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1116)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:376)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:313)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
....
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping com.MyHandlerInterceptorTest.requestMappingHandlerMapping; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration: Initialization of bean failed; nested exception is org.springframework.context.ApplicationContextException: Cannot reinitialize with different application context: current one is [Root WebApplicationContext: startup date [XXX 2016]; root of context hierarchy], passed-in one is [org.springframework.context.support.GenericApplicationContext@4760457f: startup date [Fri Mar 18 11:01:19 EST 2016]; root of context hierarchy]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:514)

似乎正在发生的事情是我的测试环境被其他测试所窃取。我想知道如何确定何时发生并停止它,或者至少解决它。

我的问题是:如何阻止其他JUnit测试窃取我的Spring Root Controller?

2 个答案:

答案 0 :(得分:1)

您可能希望将此上下文与其他测试上下文隔离开来。您可以通过name attribute of @ContextConfiguration

命名上下文来实现
@ContextConfiguration(loader = AnnotationConfigContextLoader.class,
    classes = { MyTestConfig.class }, name = "UniqueName")

答案 1 :(得分:0)

归功于@luboskrnac获得最有见地的答案。这对我来说不太合适 - 所以我写的是我最终做的事情。

我尝试在非root类加载器中隔离Web Context,如下所示:

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.mock.web.MockServletContext;
import org.springframework.web.context.support.GenericWebApplicationContext;

DefaultListableBeanFactory dlbf = new DefaultListableBeanFactory(getApplicationContext().getBeanFactory());
GenericWebApplicationContext gwac = new GenericWebApplicationContext(dlbf);
MockServletContext mockServletContext = new MockServletContext();
mockServletContext .setAttribute(GenericWebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, gwac);
gwac.setServletContext(msc);
gwac.refresh();

有趣的是 - 这实际上与@luboskrnac上面提到的相同 - 但他的解决方案更加优雅。

不幸的是,这导致了我的ehcache错误(事实证明 - 只想在JVM中加载类,无论是类加载器还是Spring-context分区)。

SEVERE: Servlet.service() for servlet [SpringDispatcher] in context with path [/FileService] threw exception [com.sun.jersey.api.container.ContainerException: Unable to create resource class com.myapp.FileStoreAccessAction] with root cause
net.sf.ehcache.CacheException: Another unnamed CacheManager already exists in the same  VM. Please provide unique names for each CacheManager in the config or do one of following:
1. Use one of the CacheManager.create() static factory methods to reuse same CacheManager with same name or create one if necessary
2. Shutdown the earlier cacheManager before creating new one with same name.
The source of the existing CacheManager is: InputStreamConfigurationSource [stream=java.io.BufferedInputStream@e782a8]

所以我最终做的是将测试作为单独的surefire测试执行的一部分运行,如下所示:

<build>
<plugins>
    <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <executions>
            <execution>
                <phase>test</phase>
                <id>test-1</id>
                <configuration>
                    ...
                </configuration>
                <goals><goal>test</goal></goals>
            </execution>
            <execution>
                <phase>test</phase>
                <id>test-2</id>
                <configuration>
                    ...
                </configuration>
                <goals><goal>test</goal></goals>
            </execution>
        </executions>
    </plugin>
</plugins>
...
</build>