테스트를 위한 애플리케이션 컨텍스트 관리
설정파일 및 의존성 주입등을 활용한 테스트 클래스 작성법에 대해 다룹니다.
스프링 테스트 컨텍스트 프레임워크 적용
스프링 테스트 컨텍스트를 적용한 UserDaoTest
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "/applicationContext.xml")
public class DBTest {
@Autowired
private ApplicationContext context;
...
@BeforeAll
public void setUp() {
this.dao = this.context.getBean("userDao", UserDao.class);
}
@ExtendWith
단위 테스트에 공통적으로 사용할 확장 기능을 선언해주는 Annotation
@ContextConfiguration
테스트에 사용할 컨텍스트 설정을 담은 클래스 혹은 xml 파일을 선언해주는 Annotation
테스트 메소드의 컨텍스트 공유
@ContextConfiguration으로 설정을 잡아주면 JUnit은 테스트 메소드를 실행할 때마다 새로운 테스트 오브젝트를 만들어준다.테스트 실행 전에 한번만 애플리케이션 컨텍스트를 만들어두고, 테스트 오브젝트가 만들어질 때마다 애플리케이션 컨텍스트 자신은 테스트 오브젝트의 특정 필드로 주입한다.
테스트 클래스의 컨텍스트 공유
수백개의 테스트 클래스를 만들어도 테스트 전체에 걸쳐 단 한개의 애플리케이션 컨텍스트만 만들어져 사용된다.
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "/applicationContext.xml") -> /applicationContext.xml
public class DBTest { ... }
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "/applicationContext.xml") -> /applicationContext.xml
public class UserDaoTest { ... }
@Autowired
스프링이 관리하는 @Bean을 자동으로 매핑해준다.
@Autowired가 붙은 인스턴스 변수가 있으면, 테스트 컨텍스트 프레임워크는 변수 타입과 일치하는 컨텍스트 내의 빈을 찾는다. 타입이 일치하는 빈이 있으면 인스턴스 변수에 주입해준다.
DI와 테스트
DI를 테스트에 적용하는 방법과 관념에 대해 다룹니다.
어떤 클래스의 구현부가 절대 바뀌지 않을것이라 가정하고 해당 클래스를 DI로 가져와야 한다고 가정해보자.
이때 직접 인스턴스 생성보다 인터페이스를 두고 DI를 적용해야한다. 그 이유는 다음과 같다.
1. 소프트웨어 개발에서 절대로 바뀌지 않는 것은 없다. (작은 수고로 변경에 대한 리스크 최소화)
2. 클래스 구현 방식이 바뀌지 않아도 인터페이스를 두고 DI를 적용하게 해두면 부가 기능 도입이 쉽다.
ex) DB 커넥션 개수 카운팅 기능 등 (AOP로 다룰 수 있지만 DI가 없다면 애초에 불가능 함)
3. 테스트때문 - 자동으로 실행 가능하며 빠르게 동작하는 테스트 코드 작성해야함. DI는 테스트가 작은 단위의 대상에 대해 독립적으로 만들어지고 실행되게 하는데 중요한 역할을 한다.
테스트 코드에 의한 DI
Run all Tests로 모든 단위 테스트 작업시 실패하는 경우가 있다 (기존 context를 재활용하여 예상과 다른 결과)
테스트시 설정파일에서 직접 운영용 DB등으로 테스팅하면 위험할 수 있다.
이를 해결하기 위해 @DirtiesConext를 활용해보자.
테스트를 위한 수동 DI를 적용한 UserDaoTest
@DirtiesContext
// 테스트 메소드에서 애플리케이션 컨텍스트의 구성이나 상태를
// 변경한다는 것을 테스트 컨텍스트 프레임워크에 알려준다.
public class UserDaoTest {
@Autowired
UserDao dao;
@BeforeAll
public void setUp() {
//...
DataSource dataSource = new SingleConnectionDataSource(
"jdbc:mysql://localhost/testdb", "spring", "book", true
);
dao.setDataSource(dataSource); // 코드에 의한 수동 DI
}
}
XML 설정파일을 수정하지 않고도 테스트 코드를 통해 오브젝트 관계를 재구성할 수 있다.
테스트 중 변경한 컨텍스트가 뒤에 테스트에 영향을 주지 않게 도와줌
메소드 레벨의 @DirtiesContext 사용하기
@DirtiesContext는 메소드 레벨에서도 적용 가능하다.
하나의 메소드에서만 컨텍스트 상태를 변경한다면 메소드 레벨에 @DirtiesContext를 붙여주는 편이 낫다.
해당 메소드의 실행이 끝나고 나면 이후에 진행되는 테스트를 위해 변경된 애프리케이션 컨텍스트는 폐기되고, 새로운 애플리케이션 컨텍스트가 만들어진다.
테스트를 위한 별도의 DI 설정
@DirtiesContext대신 테스트용 설정파일을 하나 더 만들어서 적용하는 방법도 있다.
<bean id="datasource"
class="org.springframework.jdbc.datasource.SimpleDirverDataSource" >
<property name="driverClass" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/testdb" />
<property name="username" value="spring" />
<property name="password" value="book" />
</bean>
설정파일 변경으로 수동 DI코드나 @DirtiesContext가 필요없게 되었다!
테스트용 설정 파일 적용
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "/test-applicationContext.xml")
public class UserDaoTest {
컨테이너 없는 DI 테스트
애플리케이션 컨텍스트 없는 DI 테스트
public class UserDaoTest {
UserDao dao; // @AutoWired가 없다.
...
@BeforeAll
public void setUp() {
...
dao = new UserDao();
DataSource dataSource = new SingleConnectionDataSource(
"jdbc:mysql://localhost/testdb", "spring", "book", true);
dao.setDataSource(dataSource);
}
}
침투적 기술과 비침투적 기술
침투적(invasive) 기술은 기술을 적용했을 때 애플리케이션 코드에 기술 관련 API가 등장하거나, 특정 인터페이스나 클래스를 사용하도록 강제하는 기술을 말한다. 침투적 기술을 사용하면 애플리케이션 코드가 해당 기술에 종속되는 결과를 가져온다. 반면에 비침투적(noninvasive)인 기술은 애플리케이션 로직을 담은 코드에 아무런 영향을 주지 않고 적용이 가능하다. 따라서 기술에 종속적이지 않은 순수한 코드를 유지할 수 있게 해준다. 스프링은 이런 비침투적인 기술의 대표적인 예다. 그래서 스프링 컨테이너 없는 DI 테스트도 가능한 것이다.
DI를 이용한 테스트 방법 선택
1. 스프링 컨테이너 없이 테스트할 수 있는 방법을 우선적으로 고려 ( 수행이 빠르고 간결하다. )
2. 여러 오브젝트와 복잡한 의존관계를 갖고 있는 오브젝트를 테스트 할 때 스프링 설정을 이용한 DI 방식의 테스트를 이용
3.애플리케이션 컨텍스트를 사용할 경우 테스트 전용 설정파일을 만들어 사용 ( 예외사용시 @DirtiesContext 활용)
'BackEnd > Spring & Springboot Study' 카테고리의 다른 글
[토비의 스프링] 2.6 테스트 정리 (0) | 2022.12.24 |
---|---|
[토비의 스프링] 2.5 학습 테스트로 배우는 스프링 (0) | 2022.12.23 |
[토비의 스프링] 2.3 개발자를 위한 테스팅 프레임워크 JUnit (0) | 2022.12.22 |
[토비의 스프링] 2.2 UserDaoTest 개선 (0) | 2022.12.18 |
[토비의 스프링] 2.1 UserDaoTest 다시 보기 (0) | 2022.12.12 |