상세 컨텐츠

본문 제목

[2.4] 스프링 테스트 적용

토비의스프링

by kwanghyup 2020. 10. 28. 17:27

본문

애플리케이션 컨텍스트 생성 방식을 개선해보자. 

@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&amp;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");
		
	}
	// 생략...
}

테스트를 수행하면 성공한다. 

 

 

 

 

 

 

 

관련글 더보기

댓글 영역