Question

Je voudrais utiliser la demande scope haricots dans mon application. J'utilise junit4 pour les tests. Si je tente de créer un dans un test comme celui-ci:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring/TestScopedBeans-context.xml" })
public class TestScopedBeans {
    protected final static Logger logger = Logger
            .getLogger(TestScopedBeans.class);

    @Resource
    private Object tObj;

    @Test
    public void testBean() {
        logger.debug(tObj);
    }

    @Test
    public void testBean2() {
        logger.debug(tObj);
    }

Avec la définition de haricot suivant:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean class="java.lang.Object" id="tObj" scope="request" />
 </beans>           

Et je reçois:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gov.nasa.arc.cx.sor.query.TestScopedBeans': Injection of resource fields failed; nested exception is java.lang.IllegalStateException: No Scope registered for scope 'request'
<...SNIP...>
Caused by: java.lang.IllegalStateException: No Scope registered for scope 'request'

Alors j'ai trouvé ce blog qui semblait utile: http://www.javathinking.com/2009 /06/no-scope-registered-for-scope-request_5.html

Mais je remarquai qu'il utilise AbstractDependencyInjectionSpringContextTests qui semble être dépréciée au printemps 3.0. J'utilise Spring 2.5 à ce moment, mais je pensais qu'il ne devrait pas être trop difficile de changer cette méthode pour utiliser AbstractJUnit4SpringContextTests les documents suggèrent (ok la documentation lien vers la version 3.8, mais je suis en utilisant 4.4). Alors je change la test pour étendre AbstractJUnit4SpringContextTests ... même message. Même problème. Et maintenant la méthode prepareTestInstance () Je veux à remplacer ne soit pas défini. OK, peut-être que je vais mettre les registerScope appelle un autre ... Alors, je l'ai lu plus sur

Était-ce utile?

La solution

Le test passe parce qu'il ne fait rien:)

Lorsque vous omettez l'annotation @TestExecutionListeners, enregistre Spring 3 auditeurs par défaut, dont un appelé DependencyInjectionTestExecutionListener. Ceci est l'auditeur responsable de l'analyse de votre classe de test à la recherche de choses à injecter, y compris les annotations de @Resource. Cet auditeur a essayé d'injecter tObj et échoue, en raison de la portée non définie.

Lorsque vous déclarez @TestExecutionListeners({}), vous supprimez l'enregistrement de la DependencyInjectionTestExecutionListener, et donc le test gets tObj jamais injecté du tout, et parce que votre test ne vérifie pas l'existence de tObj, il passe.

Modifier votre test pour qu'il le fait, et il échouera:

@Test
public void testBean() {
    assertNotNull("tObj is null", tObj);
}

Avec votre @TestExecutionListeners vide, le test passe parce que rien ne se passe .

Maintenant, à votre problème d'origine. Si vous voulez essayer l'enregistrement du périmètre de la requête avec votre contexte de test, puis un coup d'oeil au code source de WebApplicationContextUtils.registerWebApplicationScopes(), vous trouverez la ligne:

beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());

Vous pouvez essayer, et de voir comment vous allez, mais il pourrait y avoir des effets secondaires bizarres, parce que vous n'êtes pas vraiment l'intention de faire cela dans un test.

Au lieu de cela, je recommande reformulant votre test afin que vous ne faites pas besoin demande scope haricots. Cela ne devrait pas être difficile, le cycle de vie du @Test ne devrait pas être plus long que le cycle de vie d'un haricot scope demande, si vous écrivez des tests autonomes. Rappelez-vous, il n'y a pas besoin de tester le mécanisme de détermination de la portée, il fait partie du printemps et vous pouvez supposer qu'il fonctionne.

Autres conseils

Solution pour le printemps 3.2 ou plus récent

Printemps à partir de la version 3.2 fournit un soutien pour scope séance / demande des haricots pour les tests d'intégration .

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
@WebAppConfiguration
public class SampleTest {

    @Autowired WebApplicationContext wac;

    @Autowired MockHttpServletRequest request;

    @Autowired MockHttpSession session;    

    @Autowired MySessionBean mySessionBean;

    @Autowired MyRequestBean myRequestBean;

    @Test
    public void requestScope() throws Exception {
        assertThat(myRequestBean)
           .isSameAs(request.getAttribute("myRequestBean"));
        assertThat(myRequestBean)
           .isSameAs(wac.getBean("myRequestBean", MyRequestBean.class));
    }

    @Test
    public void sessionScope() throws Exception {
        assertThat(mySessionBean)
           .isSameAs(session.getAttribute("mySessionBean"));
        assertThat(mySessionBean)
           .isSameAs(wac.getBean("mySessionBean", MySessionBean.class));
    }
}

En savoir plus: Demande et session Scoped beans


Solution pour le printemps avant 3.2 avec l'auditeur

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
@TestExecutionListeners({WebContextTestExecutionListener.class,
        DependencyInjectionTestExecutionListener.class,
        DirtiesContextTestExecutionListener.class})
public class SampleTest {
    ...
}

WebContextTestExecutionListener.java

public  class WebContextTestExecutionListener extends AbstractTestExecutionListener {
    @Override
    public void prepareTestInstance(TestContext testContext) {
        if (testContext.getApplicationContext() instanceof GenericApplicationContext) {
            GenericApplicationContext context = (GenericApplicationContext) testContext.getApplicationContext();
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST,
                    new SimpleThreadScope());
            beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION,
                    new SimpleThreadScope());
        }
    }
}

Solution pour le printemps avant 3.2 avec champs personnalisés

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class, locations = "test-config.xml")
public class SampleTest {

...

}

TestConfig.java

@Configuration
@ComponentScan(...)
public class TestConfig {

    @Bean
    public CustomScopeConfigurer customScopeConfigurer(){
        CustomScopeConfigurer scopeConfigurer = new CustomScopeConfigurer();

        HashMap<String, Object> scopes = new HashMap<String, Object>();
        scopes.put(WebApplicationContext.SCOPE_REQUEST,
                new SimpleThreadScope());
        scopes.put(WebApplicationContext.SCOPE_SESSION,
                new SimpleThreadScope());
        scopeConfigurer.setScopes(scopes);

        return scopeConfigurer

}

ou avec la configuration xml

test-config.xml

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="request">
                <bean class="org.springframework.context.support.SimpleThreadScope"/>
            </entry>
        </map>
        <map>
            <entry key="session">
                <bean class="org.springframework.context.support.SimpleThreadScope"/>
            </entry>
        </map>
    </property>
</bean>

Code source

Le code source pour toutes les solutions présentées:

J'ai essayé plusieurs solutions, y compris @ la solution de Marius avec le « WebContextTestExecutionListener », mais il ne fonctionne pas pour moi, car ce code chargé le contexte d'application avant de créer le périmètre de la requête.

La réponse qui m'a aidé à la fin n'est pas une nouvelle, mais il est bon: http://tarunsapra.wordpress.com/2011/06 / 28 / JUnit-printemps-session et demande de portée en grains /

J'ai simplement ajouté l'extrait suivant à mon (test) contexte d'application:

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="request">
                <bean class="org.springframework.context.support.SimpleThreadScope"/>
            </entry>
        </map>
    </property>
</bean>

Bonne chance!

Une solution, testée avec Spring 4, lorsque vous avez besoin d'haricots scope demande, mais ne faites aucune demande via MockMVC, etc.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(/* ... */)
public class Tests {

    @Autowired
    private GenericApplicationContext context;

    @Before
    public void defineRequestScope() {
        context.getBeanFactory().registerScope(
            WebApplicationContext.SCOPE_REQUEST, new RequestScope());
        RequestContextHolder.setRequestAttributes(
            new ServletRequestAttributes(new MockHttpServletRequest()));
    }

    // ...

Il est encore une question ouverte:

https://jira.springsource.org/browse/SPR-4588

J'ai pu obtenir ce travail (la plupart du temps) en définissant un contexte personnalisé chargeur comme indiqué dans

http://forum.springsource.org/showthread.php?p=286280

Demande d'essai-Scoped Fèves au printemps explique très bien comment vous inscrire et créer un champ personnalisé avec le printemps.

En un mot, comme Ido Cohn a expliqué, il suffit d'ajouter ce qui suit à la configuration du contexte du texte:

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="request">
                <bean class="org.springframework.context.support.SimpleThreadScope"/>
            </entry>
        </map>
    </property>
</bean>

Au lieu d'utiliser le SimpleThreadScope prédéfini, basé sur ThreadLocal, il est également facile à mettre en œuvre un personnalisé, comme expliqué dans l'article.

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

public class CustomScope implements Scope {

    private final Map<String , Object> beanMap = new HashMap<String , Object>();

    public Object get(String name, ObjectFactory<?> factory) {
        Object bean = beanMap.get(name);
        if (null == bean) {
            bean = factory.getObject();
            beanMap.put(name, bean);
        }
        return bean;
    }

    public String getConversationId() {
        // not needed
        return null;
    }

    public void registerDestructionCallback(String arg0, Runnable arg1) {
        // not needed
    }

    public Object remove(String obj) {
        return beanMap.remove(obj);
    }

    public Object resolveContextualObject(String arg0) {
        // not needed
        return null;
    }
}

solution « MariuszS fonctionne, sauf que je ne pouvais pas me la transaction validée correctement.

Il semble que la nouvelle version 3.2 a finalement fait la demande de test / séance scope haricots citoyens de première classe. Voici quelques blogs pour plus de détails.

de

Rossen Stoyanchev Spring Framework 3.2 RC1: test Framework Spring MVC

Sam Brannen Printemps cadre 3.2 RC1: Nouveau test Caractéristiques

PAS la lecture des documents conduit parfois un fou. Presque.

Si vous utilisez des haricots plus courte durée (portée de la demande par exemple), vous avez probablement besoin aussi de changer votre défaut init paresseux! Sinon, le WebAppContext ne parviendra pas à charger et vous dire quelque chose sur la portée de la demande manquante, ce qui est évidemment manquante, parce que le contexte est toujours en cours de téléchargement!

scroll top