문제

내 앱에서 요청 범위 Bean을 사용하고 싶습니다.테스트에는 JUnit4를 사용합니다.다음과 같은 테스트에서 하나를 만들려고 하면:

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

다음 빈 정의를 사용하면:

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

그리고 나는 다음을 얻습니다:

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'

그래서 도움이 될 것 같은 이 블로그를 찾았습니다.http://www.javathinking.com/2009/06/no-scope-registered-for-scope-request_5.html

하지만 나는 그가 사용하는 것을 알아차렸습니다. AbstractDependencyInjectionSpringContext테스트 Spring 3.0에서는 더 이상 사용되지 않는 것 같습니다.나는 현재 Spring 2.5를 사용하지만 Docs가 제안한대로 AbstractJunit4SpringContextTests를 사용하기 위해이 방법을 전환하는 것이 너무 어렵지 않아야한다고 생각했습니다 (문서는 3.8 버전으로 링크하지만 4.4를 사용하고 있습니다).그래서 나는 trackJunit4SpringContextTests를 확장하기 위해 테스트를 변경합니다 ...같은 메시지.같은 문제입니다.그리고 이제 재정의하려는 repireTestInstance () 메소드는 정의되지 않았습니다.좋아, 어쩌면 그 RegisterScope 호출을 다른 곳에 둘 수도 있겠네요...그래서 나는 다음에 대해 더 많이 읽었습니다. 테스트실행리스너 그리고 스프링 패키지 구조를 상속받고 싶지 않기 때문에 그것이 더 좋을 것이라고 생각합니다.그래서 테스트를 다음으로 변경했습니다.

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

사용자 정의 리스너를 만들어야 한다고 예상했지만 실행했을 때였습니다.효과가있다!좋아요. 그런데 왜요?재고 청취자가 요청 범위 또는 세션 범위를 등록하는 곳을 어디서 알지 못하고 왜 그 이유는 무엇입니까?아직 내가 원한다고 말할 수 있는 것은 없습니다. 이것은 Spring MVC 코드에 대한 테스트가 아닐 수도 있습니다...

도움이 되었습니까?

해결책

테스트는 아무것도하지 않기 때문에 통과합니다 :)

당신이 생략 할 때 @TestExecutionListeners 주석, 스프링 레지스터 3 개의 기본 리스너 (호출)를 포함하여 기본 리스너 DependencyInjectionTestExecutionListener. 이것은 테스트 클래스를 스캔하는 청취자입니다. @Resource 주석. 이 청취자는 주사하려고했습니다 tObj, 정의되지 않은 범위 때문에 실패합니다.

당신이 선언 할 때 @TestExecutionListeners({}), 당신은 등록을 억제합니다 DependencyInjectionTestExecutionListener, 그래서 테스트는 결코 얻지 못합니다 tObj 전혀 주입하고 시험이 존재하는지 확인하지 않기 때문에 tObj, 그것은지나갑니다.

테스트가 수행되도록 테스트를 수정하면 실패합니다.

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

그래서 당신의 비어 @TestExecutionListeners, 테스트는 왜냐하면 아무 반응이 없습니다.

이제 원래의 문제에. 테스트 컨텍스트에 요청 범위를 등록하려면 소스 코드를 살펴보십시오. WebApplicationContextUtils.registerWebApplicationScopes(), 당신은 줄을 찾을 수 있습니다 :

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

당신은 그것을 시도하고 어떻게 갈 것인지 볼 수 있지만, 실제로 테스트에서 이것을해야하기 때문에 이상한 부작용이있을 수 있습니다.

대신, 나는 당신이하지 않도록 테스트를 다시 표시하는 것이 좋습니다. 필요 스코프 콩을 요청하십시오. 이것은 어렵지 않아야합니다. 수명주기 @Test 독립적 인 테스트를 작성하는 경우 요청 스코핑 Bean의 수명주기보다 더 길어서는 안됩니다. 스코핑 메커니즘을 테스트 할 필요가 없으며 스프링의 일부이며 작동한다고 가정 할 수 있습니다.

다른 팁

봄 3.2 또는 새로 사용하는 솔루션

버전 3.2로 시작하는 봄 통합 테스트를위한 세션/요청 범위 콩을 지원합니다..

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

더 읽기 : 요청 및 세션 범위 콩


청취자와 함께 3.2 이전의 스프링 솔루션

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

사용자 정의 범위로 3.2 이전의 스프링 솔루션

@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

}

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

소스 코드

제시된 모든 솔루션에 대한 소스 코드 :

"WebContextTestExecutionListener"를 사용하여 @Marius의 솔루션을 포함한 여러 솔루션을 시도했지만이 코드가 요청 범위를 작성하기 전에 응용 프로그램 컨텍스트를로드했기 때문에 작동하지 않았습니다.

결국 저를 도와 준 대답은 새로운 것이 아니지만 좋습니다.http://tarunsapra.wordpress.com/2011/06/28/junit-spring-session-and-request-scope-beans/

다음 스 니펫을 내 (테스트) 응용 프로그램 컨텍스트에 추가했습니다.

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

행운을 빕니다!

요청 스코핑 콩이 필요하지만 MockMVC, 등.

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

    // ...

이는 여전히 미해결 문제입니다.

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

다음에 설명된 대로 사용자 정의 컨텍스트 로더를 정의하여 이 작업을 (주로) 수행할 수 있었습니다.

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

스프링으로 요청 스코프 콩을 테스트하십시오 Spring과 함께 사용자 정의 범위를 등록하고 만드는 방법을 잘 설명합니다.

간단히 말해서 Ido Cohn이 설명했듯이 텍스트 컨텍스트 구성에 다음을 추가하기에 충분합니다.

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

ThreadLocal을 기반으로 사전 정의 된 SimplethreadScope를 사용하는 대신 기사에서 설명한대로 사용자 정의를 구현하기 쉽습니다.

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

Mariuszs의 솔루션은 거래를 제대로 커밋 할 수 없다는 점을 제외하고는 작동합니다.

새로 출시 된 3.2는 마침내 테스트 요청/세션 스코프 콩 주민 시민을 만들었습니다. 자세한 내용은 몇 가지 블로그가 있습니다.

로센 스토 아체프 스프링 프레임 워크 3.2 RC1 : 스프링 MVC 테스트 프레임 워크

샘 브란 넨 스프링 프레임 워크 3.2 RC1 : 새로운 테스트 기능

문서를 읽지 않으면 때때로 미친 듯이 운전합니다. 거의.

더 짧은 수명 콩을 사용하는 경우 (예 : 요청 범위) 게으른 이른 기본값도 변경해야 할 것입니다! 그렇지 않으면 webAppContext가로드되지 않아서 요청 범위가 누락 된 것에 대해 알려줍니다. 물론 컨텍스트가 여전히로드되고 있기 때문에 누락되었습니다!

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

스프링 녀석들은 확실히 그 힌트를 예외 메시지에 넣어야합니다 ...

기본값을 변경하지 않으려면 @Component 등에 "@Lazy (true)"를 넣으려면 주석이 있습니다. 싱글 톤이 게으른 초기화를 초기화하고 요청-스코핑 된 콩을 너무 일찍 인스턴스화하지 않도록하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top