Pregunta

Me gustaría hacer uso de petición en ámbito de los granos en mi aplicación. Yo uso junit4 para la prueba. Si trato de crear uno en una prueba como esta:

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

Con la siguiente definición de frijol:

 <?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>           

Y me sale:

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'

Así que encontré este blog que parecía útil: http://www.javathinking.com/2009 /06/no-scope-registered-for-scope-request_5.html

Pero me di cuenta de que él utiliza AbstractDependencyInjectionSpringContextTests que parece estar en desuso en Spring 3.0. Yo uso la primavera 2,5 en este momento, pero pensé que no debería ser demasiado difícil de cambiar este método a utilizar AbstractJUnit4SpringContextTests como sugieren los documentos (bien los documentos de enlace a la versión 3.8, pero estoy usando 4.4). Así que cambio el prueba para extender AbstractJUnit4SpringContextTests ... mismo mensaje. El mismo problema. Y ahora el método prepareTestInstance () Quiero para anular no está definido. OK, tal vez voy a poner los registerScope llama a otro lugar ... Así que leí más sobre TestExecutionListeners y pensar que sería mejor ya que no quieren tener que heredar la estructura del paquete de resorte. Entonces He cambiado de prueba a:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring/TestScopedBeans-context.xml" })
@TestExecutionListeners({})
public class TestScopedBeans {

esperando que tendría que crear un escucha personalizado pero cuando me encontré con él. ¡Funciona! Muy bien, pero ¿por qué? No veo donde cualquiera de los oyentes de valores están registrando ámbito de la petición o ámbito de sesión, y por qué lo harían? no hay nada que decir que quiero que, sin embargo, esto podría no ser una prueba para el código de Spring MVC ...

¿Fue útil?

Solución

La prueba pasa porque no está haciendo nada:)

Cuando se omite la anotación @TestExecutionListeners, Primavera registra 3 oyentes por defecto, incluyendo uno llamado DependencyInjectionTestExecutionListener. Este es el oyente responsable de escaneo de su clase de prueba en busca de cosas para inyectar, incluyendo anotaciones @Resource. Este oyente trató de inyectar tObj, y fracasa, debido al alcance definido.

Cuando se declara @TestExecutionListeners({}), se suprime el registro de la DependencyInjectionTestExecutionListener, y lo que la prueba nunca se tObj inyectó en absoluto, y debido a que su prueba no es la comprobación de la existencia de tObj, a su paso.

Modificar el script de manera que hace esto, y se producirá un error:

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

Así que con su @TestExecutionListeners vacío, se supera la prueba, porque no pasa nada .

Ahora, volviendo a su problema original. Si quieres probar registrar el ámbito de la petición con su contexto de prueba, a continuación, echar un vistazo al código fuente de WebApplicationContextUtils.registerWebApplicationScopes(), podrás encontrar la línea:

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

Usted podría intentar esto, y ver cómo se van, pero puede haber efectos secundarios extraños, porque en realidad no estás destinado a hacer esto en una prueba.

En su lugar, yo recomendaría reformular su script de manera que no lo hace necesidad petición en ámbito de los granos. Esto no debería ser difícil, el ciclo de vida de la @Test no debe ser por más tiempo que el ciclo de vida de un grano de petición con ámbito, si se escribe pruebas independientes. Recuerde, no hay necesidad de probar el mecanismo de determinación del alcance, es parte de la primavera y se puede asumir que funciona.

Otros consejos

Solución para la primavera de 3.2 o más reciente

Primavera partir de la versión 3.2 proporciona soporte para la sesión / petición en ámbito de frijoles para las pruebas de integración .

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

Leer más: noreferrer solicitud y sesión en el ámbito frijoles


Solución para la primavera antes de 3.2 con oyente

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

Solución para la primavera antes de 3.2 con ámbitos personalizados

@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

}

o con configuración 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>

El código fuente

El código fuente para todas las soluciones presentadas:

He intentado varias soluciones, incluyendo @ solución de Marius con el "WebContextTestExecutionListener", pero no funcionó para mí, ya que este código carga el contexto de aplicación antes de crear el ámbito de la petición.

La respuesta que me ayudó al final no es nuevo, pero es bueno: http://tarunsapra.wordpress.com/2011/06 / 28 / junit-primavera-session-y-petición de alcance en grano /

Simplemente añade el siguiente fragmento de mi (prueba) de contexto de aplicación:

<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>

Buena suerte!

Una solución, probada con Spring 4, para en caso de requerir granos de petición con ámbito, pero no está haciendo ninguna solicitud vía 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()));
    }

    // ...

Esto es todavía una cuestión abierta:

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

Yo era capaz de conseguir que esto funcione (en su mayoría) mediante la definición de un cargador de contexto personalizado como se describe en

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

prueba Frijoles Solicitud de ámbito de la primavera con explica muy así como registrar y crear un ámbito personalizado con la primavera.

En pocas palabras, tal como se explica Ido Cohn, es suficiente para añadir lo siguiente a la configuración del marco de texto:

<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>

En lugar de utilizar la predefinido SimpleThreadScope, basado en ThreadLocal, también es fácil de implementar uno personalizado, como se explica en el artículo.

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

solución MariuszS' funciona, excepto que no podía conseguir la transacción cometido adecuadamente.

Parece que la recién estrenada solicitud de prueba / sesión 3,2 por fin se ha hecho con ámbito granos de ciudadanos de primera clase. He aquí un par de blogs para obtener más detalles.

de Rossen Stoyanchev Spring Framework 3.2 RC1: Spring MVC marco de prueba

primavera

de Sam Brannen marco 3.2 RC1: Nueva Prueba Características

NO lectura de la documentación a veces conduce loco. Casi.

Si está utilizando granos de menor vida (alcance petición, por ejemplo), lo más probable es que también necesita cambiar su defecto init perezoso! De lo contrario el WebAppContext no se cargará y le dirá algo acerca falta ámbito de la petición, que por supuesto es que falta, porque el contexto sigue cargando!

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-factory-lazy-init

Los chicos de primavera sin duda debe poner ese toque en su mensaje de excepción ...

Si no desea cambiar el valor predeterminado, existe también la forma de anotación: poner "@Lazy (verdadero)" después de @Component etc, para hacer únicos inicializar perezoso y evitar crear instancias de solicitud de habas con ámbito demasiado pronto <. / p>

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top