Search code examples
javaspringjunitjunit4

How to use custom Spring scope with unit tests (SpringJUnit4ClassRunner)


I am using JUnit tests with Spring configuration defined in a class annotated with @Configuration in my JUnit Test. The tests looks like this:

@ContextConfiguration(classes = MyConfiguration.class})
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class SomeIntegrationTest {

    @Autowired
    private MyConfiguration myConfiguration;

    @Test
    public void someTest() throws Exception {
       myConfiguration.myBean();
    }
}

In MyConfiguration, I would like to use Spring scope SimpleThreadScope:

@Configuration
public class MyConfiguration {

    @Bean
    @Scope("thread")
    public MyBean myBean() {
        return new MyBean();
    }
}

When I run the test, the scope is not registered, though. I get

java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: java.lang.IllegalStateException: No Scope registered for scope 'thread'

I am aware how a custom scope can be registered programatically: context.getBeanFactory().registerScope("thread", new SimpleThreadScope());
and I would like to avoid using XML Spring configuration.

Is there any way, how can I register the custom scope in the unit test?


Solution

  • Check this execution listener:

    public class WebContextTestExecutionListener extends
                AbstractTestExecutionListener {
    
            @Override
            public void prepareTestInstance(TestContext testContext) throws Exception {
    
                if (testContext.getApplicationContext() instanceof GenericApplicationContext) {
                    GenericApplicationContext context = (GenericApplicationContext) testContext.getApplicationContext();
                    ConfigurableListableBeanFactory beanFactory = context
                            .getBeanFactory();
                    Scope requestScope = new SimpleThreadScope();
                    beanFactory.registerScope("request", requestScope);
                    Scope sessionScope = new SimpleThreadScope();
                    beanFactory.registerScope("session", sessionScope);
                    Scope threadScope= new SimpleThreadScope();
                    beanFactory.registerScope("thread", threadScope);
                }
            }
        }
    

    in the test you can put this

        @ContextConfiguration(classes = MyConfiguration.class})
        @RunWith(SpringJUnit4ClassRunner.class)
        @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
        @TestExecutionListeners( { WebContextTestExecutionListener.class})
        public class UserSpringIntegrationTest {
    
        @Autowired
        private UserBean userBean;
    
        //All the test methods
        }