Whiteship's Note

[스프링 테스트 확장] static member class를 빈으로 등록하는 테스트 로더 1

모하니?/Coding : 2009. 12. 18. 13:19


테스트를 편하게 하기위한 기발한 아이디어를 읽는 도중 조금 맘에 안 드는 부분이 있었는데.. 그건 바로 ApplicationContext를 직접 생성하는 부분이었습니다. 게다가 원래는 @Configuration이 붙어있는 클래스를 넘겨받기로 되어있는 API에 static membe class를 넣어 빈으로 만들었습니다. 굉장히 기발하지만 약간 해킹스러운 방식이고 불편한 점들이 보였습니다. 빈으로 등록할 static member class가 많아지기라도 하다면.. 흠..

그래서 static member class를 빈으로 등록하겠다는 명시적인 이름을 가지고 있는 테스트 컨텍트스 로더를 만들기로 했습니다. 몇일전에 만들었던 애노테이션 설정 컨텍스트 로더를 조금만 고치면 가능할 것 같아서 시도했습니다.

그 결과 다음과 같이 테스트를 작성할 수 있게됐습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = StaticMemberClassLoader.class)
public class StaticInnerConfigTest {

    @Autowired ApplicationContext ac;

    static class Hello {
        @Inject Printer printer;
    }

    static class Printer {
    }

    class Foo {}

    @Test
    public void inject() {
        for(String beanName : ac.getBeanDefinitionNames()){
            System.out.println(beanName);
        }

        Hello hello = ac.getBean(Hello.class);
        assertThat(hello.printer, is(notNullValue()));
    }
}

사부님이 작성한것과 비교하자면, 우선 ApplicationContext를 직접 만들지 않아도 알아서 static member class를 빈으로 만들어주며, static member class를 ContextConfigruation으로 쓰겠다고 로더 설정이 되어있으니 좀 더 명시적이라고 할 수 있겠습니다. 음헤헷;


콘솔에는 위와 같이 찍힙니다. StaticMemberClassLoader를 확장하거나 수정하여 빈을 등록할 때 빈 이름이나, 등록할 빈을 골라내는 작업을 얼마든지 변경할 수도 있습니다.

사부님 덕분에 아침부터 잼난 코딩을 했더니 기분이좋습니다. 참고로 이 로더 구현체에는 문제가 좀 많습니다. 무슨 문제가 있는지 지적해주시는 분이 계실지 모르겠지만 퀴즈 삼아 문제가 많은 코드를 공유하고 싶어졌습니다. 발코딩을 까고 싶으신 분들에게는 절호의 기회입니다. 마음껏 까주세요!

public class StaticMemberClassLoader extends AnnotationContextLoader {

    @Override
    protected void createCustomBean(DefaultListableBeanFactory context, String[] locations) throws ClassNotFoundException {
        for(String string : locations){
            Class beanClass = ClassUtils.forName(string, getClass().getClassLoader());
            context.registerBeanDefinition(beanClass.getSimpleName(), BeanDefinitionBuilder.rootBeanDefinition(beanClass).getBeanDefinition());
        }
    }

    @Override
    protected String[] generateDefaultLocations(Class<?> clazz) {
        Class[] classes = clazz.getDeclaredClasses();
        List<String> modifiedLocations = new ArrayList<String>();
        for (int i = 0; i < classes.length; i++) {
            Class klass = classes[i];
            if(klass.getModifiers() == Modifier.STATIC)
                modifiedLocations.add(klass.getName());
        }
        return modifiedLocations.toArray(new String[modifiedLocations.size()]);
    }

}


top

  1. Favicon of http://helols.pe.kr BlogIcon is_Yoon 2009.12.18 13:31 PERM. MOD/DEL REPLY

    Class klass = classes[i];
    if(klass.getModifiers() == Modifier.STATIC)
    modifiedLocations.add(klass.getName());
    }

    klass 가 인상깊음.. ㅡㅡ;;

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.12.18 14:03 신고 PERM MOD/DEL

    뭐 그런걸 가지고.. clazz에 비하면;

  2. Favicon of http://whiteship.me BlogIcon 보아뱀 2009.12.18 16:12 PERM. MOD/DEL REPLY

    locations를 주면 뭔가 꼬일 것 같은데, 그런 경우를 방지해야 하지 않을까요?
    그리고 확장한 클래스가 AnnotationContextLoader 인데, 그것보다 상위의 클래스를 확장하는게 더 어울린다고 생각합니다.

    Favicon of http://whiteship.me BlogIcon 기선 2009.12.18 16:12 PERM MOD/DEL

    아.. 그렇군요.
    수정하겠습니다!

  3. Favicon of http://toby.epril.com BlogIcon 토비 2009.12.18 16:14 PERM. MOD/DEL REPLY

    이렇게 만들면 테스트 당 하나의 빈 조합 밖에 안나온 다는 사실.

    학습 테스트를 만들려면 매 테스트 마다 다른 빈 클래스들을 써야 하니까 직접 만들어 쓴 거지.

    Favicon of http://whiteship.me BlogIcon 기선 2009.12.18 16:35 PERM MOD/DEL

    아핫;; 그렇군요.ㅋ

Write a comment.




: 1 : ··· : 241 : 242 : 243 : 244 : 245 : 246 : 247 : 248 : 249 : ··· : 2638 :