1일1배움/Spring (김영한 님)

[23/04/13] @Autowired가 붙은 ApplicationContext 인스턴스 변수

kim chan jin 2023. 4. 13. 10:51
@RunWith(SpringJUnit4ClassRunner.class) // JUnit 확장기능은 테스트 전에 딱 한번 테스트용 ApplicationContext를 만들고 관리
@ContextConfiguration(location="/applicationContext.xml") // 읽어야 할 구성 정보의 위치
public class AutowiredInstanceTest { // 테스트 클래스 -> 테스트 오브젝트
    @Autowired
    private ApplicationContext ac; 
    // 스프링 애플리케이션 컨텍스트(AnnotationConfigApplicataionContext 등)는 (?) 초기화할 때 자기 자신도 빈으로 등록한다
    // 따라서 애플리케이션 컨텍스트에는 ApplicationContext 타입의 빈이 존재하는 셈이고 테스트용 ApplicationContext DI도 가능
    // 매번 테스트 오브젝트가 만들질 때마다 단 하나의 테스트용 ApplicationContext가 주입됨
    
    private UserDao userDao;
    private User user1;
    private User user2;
    private User user3;
    
    @Before
    public void setUp() {
        this.userDao = this.ac.getBean("userDao", UserDao.class);

        this.user1 = new User("KCJ", "김찬진", "1234");
        this.user2 = new User("AGJ", "안금장", "1234");
        this.user3 = new User("GSW", "강승원", "1234");

        System.out.println(this.ac); // @RunWith, @ContextConfiguration 덕분에 테스트 오브젝트에서 단 하나의 테스트용 ApplicationContext를 공유함
        System.out.println(this); // 2. @Test 메소드마다 테스트 오브젝트를 생성하므로 매번 새로운 메모리 주소가 출력
        
        // 1. 테스트 클래스(class hello.core.CharTest2)에서 @Test가 붙은 public이고 void형이며 파라미터가 없는 테스트 메소드를 모두 찾음
        // 2. 테스트 클래스의 오브젝트를 하나 만든다
        // 3. @Before가 붙은 메소드가 있으면 실행한다
        // 4. @Test가 붙은 메소드를 하나 호출하고 테스트 결과를 저장
        // 5. @After가 붙은 메소드가 있으면 실행한다
        // 6. 나머지 테스트 메소드에 대해 2번 ~ 5번을 반복
        // 7. 모든 테스트의 결과를 종합해서 돌려줌
    }

    @Test
    public void addAndGet() {
        // test 코드
    }

    @Test
    public void count() {
        // test 코드
    }

    @Test
    public void getUserFailure() {
        // test 코드
    }
}

 

나는 ApplicationContext ac 라는 참조변수를 빈에 등록한 적이 없다.

@Bean을 적어준 적이 없다는 것이다.

심지어 생성자 DI도, 수정자 메소드 DI도 한 적이 없다.

근데 어떻게 참조변수 ac에 테스트용 ApplicationContext가 DI 되는걸까?

 

그 이유는 참조변수 ac가 초기화될 때,

즉 JUnit 확장기능(@RunWith, @ContextConfiguration)이 단 하나의 테스트용 ApplicationContext 를 만들고 이를 참조변수 ac에 주입을 해줄 때,

참조변수 ac 자기자신도 빈으로 등록되기 때문이다.

그래서 컨테이너 속에서 ac에게 테스트용 ApplicationContext가 DI 되는 것이다.

그럼 결과적으로 테스트를 할 때마다 매번 테스트용 ApplicationContext(컨테이너)를 만드는 것이 아니라 단 하나의 테스트용 ApplicationContext를 가지고 테스트를 할 수 있게 된다.

 

단, 잊지 말아야 할 것은 테스트용 ApplicationContext는 하나를 공유할지라도 테스트 객체(여기선 AutowiredInstanceTest 객체)는 매번 만들어진다는 것이다.

@Test 어노테이션이 붙은 메소드를 하나씩 실행하기 전 테스트 객체가 매번 만들어지는 이유는 테스트들이 독립적으로 실행되기 위한 목적이다.