애플리케이션 컨텍스트 생성 방식을 개선해보자.
@Before메소드는 테스트 메소드 수 만큼 반복되기 때문에
애플리케이션 컨텍스트도 그 만큼 생성된다.
어떤 빈은 오브젝트가 생성될 때
자체적인 초기화 작업을 진행해서
제법 많은 시간이 걸린다.
또 다른 문제점은 애플리케이션 컨텍스트가 초기화될 때
많은 리소스를 할당하거나 독립적인 스레드를 띄운다.
할당 된 리소드 등이 정리되지 않으면 다음 테스트에서
애플리케이션 컨텍스트가 만들어 질 때 많은 문제를 유발한다.
UserDao의 빈을 가져다가 add(), get()메소드 등이
공유하여 사용한다고해서 UserDao의 상태가 바뀌지 않는다.
따라서 애플리케이션 컨텍스트는 한번만 만들고
여러 테스트가 공유해서 사용할 수 있다.
테스트를 위한 애플리케이션 컨텍스트 관리
pom.xml에 spring-test 의존설정을 추가한다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
@ContextConfiguration와 SpringJUnit4ClassRunner 객체는
spring-test 의존설정이 있어야 사용가능하다.
UserDaoTest를 다음과 같이 수정한다.
@RunWith(SpringJUnit4ClassRunner.class) // 스프링 테스트 컨텍스트 프레임워크의 JUnit확장기능 지정
@ContextConfiguration(locations = "/applicationContext.xml")
//테스트 컨텍스트가 자동으로 만들어줄 애플리케이션 컨텍스트 위치지정
public class UserDaoTest {
@Autowired
private ApplicationContext context;
//테스트 오브젝트가 만들어지고나면 스프링 테스트 컨텍스트에 의해 자동으로 값이 주입된다.
private UserDao dao;
private User user1;
private User user2;
private User user3;
@Before
public void setUp() {
this.dao = this.context.getBean("userDao", UserDao.class);
user1 = new User("gyumee", "박상철", "springno1");
user2 = new User("leegw700", "이길원", "springno2");
user3 = new User("bumjin", "박범진", "springno3");
}
// 테스트 메소드 생략 ...
}
테스트를 수행해본다.
ApplicationContext ctx = new GenericXmlApplicationContext("applicationContext.xml");
GenericXmlApplicationContext객체의 경로를 지정할 때에는
위와 같이 루트(/)생략이 가능했다.
그런데 @ContextConfiguration의 locations을 지정할 때에는
다음과 같이 루트(/)를 생략하면 클래스패스를 찾을 수가 없다는 오류가 난다.
@ContextConfiguration(locations = "applicationContext.xml") //Error!
@ContextConfiguration(locations = "/applicationContext.xml") //OK.
@Autowired를 이용하면 애플리케이션 컨테스트가 갖고 있는 빈을 DI받을 수 있다.
그렇다면 굳이 이 컨텍스트를 가져와 getBean()을 사용하는 것이 아닌
아에 UserDao빈을 직접 DI받을 수 있을 것이다.
UserDaoTest를 다음과 같이 수정하자.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/applicationContext.xml")
public class UserDaoTest {
//삭제한다.
//@Autowired
//private ApplicationContext context;
// UserDao에 직접 @Autowired 추가
@Autowired
private UserDao dao;
private User user1;
private User user2;
private User user3;
@Before
public void setUp() {
// 삭제한다.
//this.dao = this.context.getBean("userDao", UserDao.class);
user1 = new User("gyumee", "박상철", "springno1");
user2 = new User("leegw700", "이길원", "springno2");
user3 = new User("bumjin", "박범진", "springno3");
}
// 테스트 메소드 생략
}
테스트 코드에 의한 DI
테스트용 DB에 연결해주는 DataSource를
테스트 내에 직접 만들수 있다.
Datasource구현 클래스는 스프링이 제공하는 가장 빠른다
SingleConnectionDataSource를 사용해보자.
먼저 아래와 같이 테스트DB를 생성한다.
# 테스트 DB
drop database if exists testdb;
create database testdb;
use testdb;
drop table if exists users;
create table users(
id varchar(10) primary key,
name varchar(20) not null,
password varchar(20) not null
);
테스트 컨텍스트 프레임워크에게
테스트용DB을 사용할 것이라고 알려주어야 한다.
이런 역할을 하는 것이 @DirtiesContext 애노테이션이다.
@Before메소드에서 DataSource 오브젝트를 생성하고
이것을 UserDao 오브젝트에 직접 주입할 것이다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/applicationContext.xml")
@DirtiesContext
// 애플리케이션 컨텍스트의 구성이나 상태 변경을
// 테스트 컨텍스 프레임워크에게 알려준다.
// 이 애노테이션이 붙은 클래스에는 애플리케이션 컨텍스트를 허용하지 않는다.
public class UserDaoTest {
@Autowired
private UserDao dao;
private User user1;
private User user2;
private User user3;
@Before
public void setUp() {
// UserDao가 사용할 DataSource 오브젝트를 직접 생성하고 주입한다.
String url = "jdbc:mysql://localhost:3306/testdb?"
+ "characterEncoding=utf8&serverTimezone=UTC";
DataSource dataSource = new SingleConnectionDataSource(url,"root","12345678",true);
dao.setDataSource(dataSource);
// end
user1 = new User("gyumee", "박상철", "springno1");
user2 = new User("leegw700", "이길원", "springno2");
user3 = new User("bumjin", "박범진", "springno3");
}
// 테스트 메소드 생략...
}
(@DirtiesContext 애노테이션는 메소드 레벨에서도 사용할 수 있다.)
테스트를 수행하면 성공한다.
테스트를 위한 별도 DI설정
테스트에서 사용될 DataSource클래스가 빈으로 정의된
테스트 전용 설정파일을 만들어보자.
test-applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/testdb?characterEncoding=utf8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="12345678"/>
</bean>
<bean id="userDao" class="springbook.user.dao.UserDao">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
UserDaoTest의 @ContextConfiguration - locations엘리먼트 값을 수정한다.
@DirtiesContext애노테이션을 삭제하고
@Before메소드 내 DataSource를 직접 DI하는 코드도 제거한다.
@RunWith(SpringJUnit4ClassRunner.class)
// locations 값을 수정한다.
@ContextConfiguration(locations = "/test-applicationContext.xml")
//삭제 @DirtiesContext
public class UserDaoTest {
@Autowired
private UserDao dao;
private User user1;
private User user2;
private User user3;
@Before
public void setUp() {
/* 삭제
String url = "jdbc:mysql://localhost:3306/testdb?"
+ "characterEncoding=utf8&serverTimezone=UTC";
DataSource dataSource = new SingleConnectionDataSource(url,"root","12345678",true);
dao.setDataSource(dataSource);
*/
user1 = new User("gyumee", "박상철", "springno1");
user2 = new User("leegw700", "이길원", "springno2");
user3 = new User("bumjin", "박범진", "springno3");
}
// 생략 ...
}
이제 설정파일을 하나 더 작성하고
테스트에 맞게 수정해주는 수고만으로
테스트에 적합한 오브젝트 의존관계를 만들어 사용할 수 있게 된다.
컨테이너 없는 DI 테스트
스프링 컨테이너를 이용하지 않고 테스트를 만들어보자.
스프링 컨테이너에서 UserDao가
잘 동작하는가 확인하는 것은
UserDaoTest의 관심사가 아니다.
UserDaoTest는 UserDao 코드가 DAO코드로서
DB정보에 잘 등록하고 잘 가져오는지 확인만 하면된다.
// 애노테이션 삭제
public class UserDaoTest {
private UserDao dao;
private User user1;
private User user2;
private User user3;
@Before
public void setUp() {
// 오브젝트 생성과 관계설정을 직접 해준다.
dao = new UserDao();
String url = "jdbc:mysql://localhost:3306/testdb?"
+ "characterEncoding=utf8&serverTimezone=UTC";
DataSource dataSource = new SingleConnectionDataSource(url,"root","12345678",true);
dao.setDataSource(dataSource);
// end
user1 = new User("gyumee", "박상철", "springno1");
user2 = new User("leegw700", "이길원", "springno2");
user3 = new User("bumjin", "박범진", "springno3");
}
// 생략...
}
테스트를 수행하면 성공한다.
[3.2] 변하는 것과 변하지 않는 것 (0) | 2020.10.28 |
---|---|
[3.1] 다시 보는 초난감DAO (0) | 2020.10.28 |
[2.3] 개발자를 위한 테스팅 프레임워크 Junit (0) | 2020.10.28 |
[1.8] XML을 이용한 설정 (0) | 2020.10.27 |
[1.7] 의존관계 주입 (0) | 2020.10.27 |
댓글 영역