6장 테스트 컨텍스트 프레임워크
토비의 스프링 2권 6장을 요약한 내용 입니다.
6.1 테스트 컨텍스트 프레임워크
스프링은 테스트에 사용되는 애플리케이션 컨텍스트를 생성하고 관리하고 테스트에 적용해주는 기능을 가진 테스트 프레임워크를 제공한다. 이를 테스트 컨텍스트 프레임워크라고 부른다.
자바에서 가장 많이 사용되는 테스트 프레임워크로는 JUnit과 TestNG가 있다.
테스트용 애플리케이션 컨텍스트 캐싱과 설정파일
Junit은 테스트 메소드를 실행할 때마다 매번 테스트 클래스의 새로운 오브젝트를 만든다. 따라서 모든 테스트는 서로 영향을 주지 않으며 독립적으로 실행됨을 보장한다.
문제는 테스트가 독립적이라고 해서 매번 스프링 컨텍스트, 즉 컨테이너를 새로 만드는 건 매우 비효율적인 방법이다.
하이버네이트와 같은 ORM은 초기에 엔티티에 대한 정보를 가져와 세션을 지원할 준비 작업을 하고 스레드를 생성하는 등의 많은 부가 작업을 필요로 한다.
스프링은 테스트가 사용하는 컨텍스트를 캐싱해서 여러 테스트에서 하나의 컨텍스트를 공유할 수 있는 방법을 제공한다. (713p 그림 6-1 참고)
테스트에 테스트 컨텍스트 프레임워크를 적용하려면 테스트 클래스에 두 가지 애노테이션을 부여해줘야 한다.
먼저 @RunWith 애노테이션을 이용해서 JUnit 테스트를 실행하는 러너(Runner)를 스프링이 제공하는 것으로 변경해줘야 한다.
컨텍스트의 설정파일을 지정하여 같은 테스트 클래스안의 테스트 메소드들은 하나의 설정파일로 만들어지는 애플리케이션 컨텍스트를 공유할수 있도록 한다. ( 설정파일 이름을 생략할 경우 현재 클래스 이름에 '-context.xml'이 붙은 파일이 디폴트 설정파일 이름으로 사용된다.
컨텍스트 설정의 상속과 컨텍스트 로더
테스트 클래스를 구성할 때 필요하면 상속구조를 활용할 수도 있다.
컨텍스트 파일 정보는 상속되어 서브클래스의 컨텍스트 파일 정보는 슈퍼클래스에서 정의된 것까지 포함된다.
공유 컨텍스트 사용 시 주의할 점
캐싱 기법을 통해 하나의 컨텍스트를 여러 테스트가 공유할 수 있다는건 분명 테스트 컨텍스트 프레임워크의 장점이다.
하지만 컨텍스트를 공유하는 테스트 메소드는 컨텍스트가 자신이 독점하는 것이 아니므로 그 구성이나 내부 정보를 함부로 변경해서는 안된다.
그럼에도 어쩔 수 없이 컨텍스트의 빈 오브젝트를 조작하고 수정하는 작업이 꼭 필요한 테스트가 있을 수 도 있다.
@DirtiesContext 애노테이션이 붙은 테스트가 수행되고 나면 스프링은 현 테스트 컨텍스트를 강제로 제거한다. (메소드 뿐만 아니라 클래스 레벨에 부여할 수도 있다.)
DAO 단독 테스트
DAO를 개발한 후에 서비스 계층을 거치지 않고 직접 DAO만 테스트해야 할 때가 있다. 문제는 JPA나 하이버네이트 등으로 만든 DAO는 트랜잭션이 시작되지 않은 채로 엔티티 메니저나 세션을 사용하면 예외가 발생한다는 점이다.
그렇다고 DAO 다독 테스트를 하기 위해 서비스 계층을 매번 이용하거나 트랜잭션이 적용된 테스트용 서비스 계층 코드를 만드는 것도 매우 번거롭다.
롤백 테스트
롤백테스트란 테스트에서 진행되는 모든 DB 작업을 하나의 트랜잭션으로 묶어서 진행하고, 테스트를 마칠 때 츠랜잭션을 모두 롤백시키는 것이다.
트랜잭션 매니저
테스트에서는 TransactionTemplate 과 TransactionCalklback을 이용해 트랜잭션 경계를 설정한 후에 DB를 사용하는 빈을 호출해서 테스트를 진행한다. 테스트 메소드가 끝나고 나면 테스트에서 사용한 dao가 수정한 DB 데이터는 모두 테스트를 실행하기 이전 상태로 복구될 것이다.
@Transactional 테스트
테스트의 @Transactional은 강제롤백 옵션이 설정된 트랜잭션으로 만들어진다는 점이다. TransactionStatus의 setRollbackOnly()가 호출되는 것과 동일한 방식으로 동작한다.
트랜잭션이 시작되기 전이나 트랜잭션이 완전히 종료된 후에 해야할 작업이 있을 수도 있다. 이런 경우에는 스프링이 제공한 @beforetransaction과 @AfterTransaction이 붙은 메소드를 사용하면 된다.
ORM 롤백 트랜잭션 테스트의 주의사항
ORM은 기본적으로 모든 작업 결과를 바로 DB에 반영하지 않는다. 대신 가능한 한 오랫동안 메모리에 변경사항을 저장하고 있다가 꼭 필요한 시점에서 DB에 반영한다.
최적화를 위한 트랜잭션 내의 캐싱 기법이라고 볼수 있다.
ORM의 엔티티 오브젝트를 이용한 작업을 SQL로 만들어 DB로 보내는 작업을 플러스(flush)라고 한다.
Last updated