1

I have a JUnit test that looks like this - it is part of a larger application.

@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);
    }
}

When I run my test in isolation - it runs fine.

When I run it as part of a suite of other tests - I get the error

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)

What appears to be happening is that my test context is stolen by other tests. I want to know how to identify when this occurs and stop it, or at least work around it.

My question is: How do I stop other JUnit tests stealing my Spring Root Controller?

hawkeye
  • 34,745
  • 30
  • 150
  • 304

2 Answers2

1

You may want to isolate this context from other testing contexts. You can do it by naming the context via name attribute of @ContextConfiguration:

@ContextConfiguration(loader = AnnotationConfigContextLoader.class,
    classes = { MyTestConfig.class }, name = "UniqueName")
luboskrnac
  • 23,973
  • 10
  • 81
  • 92
  • Brilliant suggestion. A much more terse way of doing http://www.jroller.com/arondight/entry/mocking_a_webapplicationcontext_in_order . Unfortunately both of these run into errors with http://stackoverflow.com/questions/10013288/another-unnamed-cachemanager-already-exists-in-the-same-vm-ehcache-2-5 I'll write up what I did - basically this http://stackoverflow.com/questions/7239786/how-to-invoke-the-same-maven-build-twice-in-one-call – hawkeye Mar 20 '16 at 22:17
0

The credit goes to @luboskrnac for the most insightful answer. It didn't quite work out for me - so I'm writing up what I ended up doing.

I tried isolating the Web Context in a non-root class-loader like so:

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();

Interestingly enough - this is effectively the same as what @luboskrnac suggested above - but his solution is much more elegant.

Unfortunately this lead to an error with my ehcache (which it turns out - only wants to be class-loaded once inside a JVM, regardless of class-loader or Spring-context partitioning).

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]

So what I ended up doing was running the test as part of a separate surefire test execution like this:

<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>
hawkeye
  • 34,745
  • 30
  • 150
  • 304