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