테스트 두개를 동시에 돌렸을 경우 왜 밸류값이 달라지는 건가요??
141
작성한 질문수 3
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이지만 각 테스트가 시작할 때 새로 생성되고, 테스트 종료시에 제거되기 때문에 그 참조가 다르게 출력되는 것입니다.
0
따라서 컨테이너를 인스턴스 변수가 아니라 static으로 선언하여 클래스 수준에서 유지하면 모든 테스트에서 동일한 컨테이너를 사용하기 때문에 싱글톤 컨테이너에 의해 객체 참조가 동일함이 보장됩니다.
static AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
0
답변하다가 추가적으로 궁금한 부분이 생겨 챗지피티에게 물어보니
"지금은 자바 코드로 직접 테스트하고 있지만, @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 캐시를 사용하기 때문입니다.
구현체가 동적으로 정해질 때, 팩토리 기법을 사용하나요?
0
47
2
MemberService의 인터페이스를 왜 사용하는지 궁금합니다.
0
72
1
롬복 @Setter를 써야 하는 상황이 있는건가요?
0
87
1
빈 등록 메서드의 파라미터가 빈이 아니어도 되나요?
0
79
1
테스트 속도가 나중에 영향이 있을까요?
0
75
1
gradle 설정 안떠서 질문 남깁니다!
0
116
2
build.gradle로 프로젝트를 여는 이유
0
81
1
provider 사용하는 이유
0
85
1
다음 강의 뭘 들어야 할까요
0
123
2
프로토타입 빈, 직접 destroy 호출 안 할 경우
0
62
1
beanB
0
79
2
퀴즈다시풀기
0
63
1
Gradle로 바꿔도 오류가 똑같이 발생하네요 ㅠㅠ
0
90
2
"중복 등록과 충돌" 강의에서 강사님과 다른 에러가 발생합니다.
0
63
3
run 실행했는데 결과창이 이렇게 뜨네요 왜 그런건가요>
0
102
2
도메인의 정의?
0
57
1
ApplicationContext 질문입니다.
0
60
1
@Scope의 proxyMode를 사용할때 단위 테스트 방법
0
86
2
ai api 선정하기 관련 질문
0
115
2
생성자 자동주입 관련해서
0
60
1
생성자 직접 호출 vs 팩토리 메서드 패턴
0
93
2
Spring에서 SessionScope와 RequestScope는 함께 사용되나요?
1
63
1
12:25
0
74
2
appConfig.xml 오류
0
124
1





