1

I need to execute an integration test that depends on session beans. But, I don't want to use the @WepAppConfiguration because it's so time consuming.

For now, I'm using SpringRunner and ContextConfiguration to solve beans dependencies, the tests executes very fast. But, there is some code that I need to mock the session beans, and I want to do that without the use @WebAppConfiguration because it's so time consuming.

Test class:

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = TestContextSpringConfig.class)
public class MethodTest {

    @Autowired
    private BeanSession beanSession;
}

Spring configuration class:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("net.foo")
public class TestContextSpringConfig {

    @Bean // Fancy bean
    public ConfigurationPackages configurationPackages() {
        return new ConfigurationPackages();
    }

    // How to mock the session bean?

}

I expect the test to execute without throwing the following error:

java.lang.IllegalStateException: No Scope registered for scope name 'session'
João Pedro Schmitt
  • 1,046
  • 1
  • 11
  • 25

1 Answers1

0

I found the answer. The response is a mix of this POST stackoverflow with this one memorynotfound.

In this setting, I starts a thread scope for each method of Junit test simulating a "session" scope. What I've done was to create the following configuration:

@Configuration
@ComponentScan("net.foo")
public class TestContextSpringConfig {

    @Bean
    public ConfigurationPackages configurationPackages() {
        return new ConfigurationPackages();
    }

    @Bean
    public CustomScopeConfigurer customScope() {
        CustomScopeConfigurer configurer = new CustomScopeConfigurer();
        Map<String, Object> sessionScope = new HashMap<>();
        sessionScope.put("session", new ThreadScope());
        configurer.setScopes(sessionScope);
        return configurer;
    }
}

The following ThreadScope:

package net.weg.maestro;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.core.NamedThreadLocal;
import java.util.HashMap;
import java.util.Map;

public class ThreadScope implements Scope {

    private final ThreadLocal<Map<String, Object>> threadScope =
            new NamedThreadLocal<Map<String, Object>>(ThreadScope.class.getName()) {
                @Override
                protected Map<String, Object> initialValue() {
                    return new HashMap<String, Object>();
                }
            };

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> scope = this.threadScope.get();
        Object object = scope.get(name);
        if (object == null) {
            object = objectFactory.getObject();
            scope.put(name, object);
        }
        return object;
    }

    @Override
    public Object remove(String name) {
        Map<String, Object> scope = this.threadScope.get();
        return scope.remove(name);
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
    }

    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }

    @Override
    public String getConversationId() {
        return Thread.currentThread().getName();
    }

    public void clear(){
        Map<String, Object> scope = this.threadScope.get();
        scope.clear();
    }
}

And the unit tests now have access to session beans in a sandbox environment (ThreadLocal).

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = TestContextSpringConfig.class)
public class MethodTest {

    @Autowired
    private BeanSession beanSession; // Session bean

@Test
    public void parameterReachabilityTest() {
        ObjectA objectA = new ObjectA();
        ObjectB objectB = new ObjectB();
        objectA.getObjectBList().add(objectB);
        objectB.setObjectA(objectA);
        beanSession.setRootState(objectA); // Using session bean
        ObjectBComponent objectBComponent = maestro.getComp(objectB, ObjectBComponent.class);
        objectBComponent.parameterReachableTest();
        assertThat((Object) objectBComponent.getThreadValue("objectBComponent")).isNotNull();
        assertThat((Object) objectBComponent.getThreadValue("objectAComponent")).isNotNull();
    }
}
João Pedro Schmitt
  • 1,046
  • 1
  • 11
  • 25