작성
·
102
0
public class ApplicationContextInfoTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("모든 빈 출력하기")
void findAllBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + " Object = " + bean);
}
}
@Test
@DisplayName("모든 빈 출력하기")
void findApplicationAllBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + " Object = " + bean);
}
}
}
}
테스트 코드를 이렇게 짠 후 같이 돌리면 오브젝트로 나오는 애들 코드가 각각 다르게 나옵니다.
스프링 컨테이너는 초기에 한 번만 생성/등록되고 각각의 테스트에서 같은 것을 가져오는 건줄 알았는데 아닌가요..??
답변 2
1
제가 스프링은 아직 배워가는 단계라 답변이 정확하지는 않을 수도 있으나 제가 이해한 내용을 기반으로 설명드리겠습니다.
(config 파일에 @Configuration
애노테이션을 달았다는 가정하에) 스프링 컨테이너는 질문자님이 말씀하신 것처럼 싱글톤으로 작동하는 것이 맞습니다.
다만, 각 Test는 독립적으로 실행되기 때문에 다음과 같이 진행됩니다.
각 테스트마다 현재 테스트에 대한 테스트 클래스의 인스턴스 생성
이 과정에서 field(컨테이너)도 당연히 초기화
(이때 컨테이너는 싱글톤 컨테이너가 맞음)
해당 테스트 진행
해당 테스트 완료시 사용한 인스턴스 정리
(따라서 다음 테스트에서는 새롭게 컨테이너를 초기화)
(즉 다음 테스트에서는 컨테이너 자체가 다른 컨테이너이고, bean도 새로 생성해서 넣기 때문에 그 참조도 당연히 다름)
따라서 동일한 이름의 bean이지만 각 테스트가 시작할 때 새로 생성되고, 테스트 종료시에 제거되기 때문에 그 참조가 다르게 출력되는 것입니다.
답변하다가 추가적으로 궁금한 부분이 생겨 챗지피티에게 물어보니
"지금은 자바 코드로 직접 테스트하고 있지만, @SpringBootTest
를 통해서 스프링 부트를 통해 테스트를 하도록 하면 내부적으로 캐시를 사용하여 각 테스트에서 동일한 컨테이너와 빈 인스턴스를 사용합니다."
라고 답변을 해 주네요. 그런데 이 부분은 제가 아직 학습하지 않아서 설명은 못드리겠고, 추가적으로 학습하실 때 도움이 될까 해서 글로 남깁니다.
// 반대로, Spring 테스트를 제대로 쓰면?
@SpringBootTest
class MyTest {
@Autowired
ApplicationContext ac;
@Test
void test1() {
Object bean = ac.getBean("memberService");
System.out.println(System.identityHashCode(bean));
}
@Test
void test2() {
Object bean = ac.getBean("memberService");
System.out.println(System.identityHashCode(bean)); // 위와 동일한 hashCode
}
}
// 이렇게 하면 두 테스트 모두 같은 컨테이너, 같은 빈 인스턴스를 사용합니다.
// 이건 스프링이 ApplicationContext 캐시를 사용하기 때문입니다.
따라서 컨테이너를 인스턴스 변수가 아니라 static으로 선언하여 클래스 수준에서 유지하면 모든 테스트에서 동일한 컨테이너를 사용하기 때문에 싱글톤 컨테이너에 의해 객체 참조가 동일함이 보장됩니다.