우선 pom.xml 을 수정하여 JUnit, Spring context, Spring test 라이브러리들을 추가합니다.
package org.edwith.webbe.calculatorcli;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"org.edwith.webbe.calculatorcli"})
public class ApplicationConfig {
}
그 다음 스프링 프레임워크를 사용하려면 스프링 설정 파일을 작성해야 한다고 배웠었는데요. 스프링 설정 파일은 xml 파일이나 @Configuration & @ComponentScan 애노테이션을 활용한 Java Config 로 작성할 수 있습니다. @Configuration 애노테이션은 스프링 설정 파일이라는 것을 의미하고 스프링 설정 파일은 스프링 빈 컨테이너인 ApplicationContext 에서 읽어 들인다고 했습니다. ( 다음 포스팅 참조 https://benprogram.tistory.com/327 ) @ComponentScan 은 특정 패키지 이하에서만 컴포넌트를 찾도록 제한합니다. @ComponentScan 애노테이션으로 지정된 패키지 이하에 @Component, @Repository, @Service, @Controller, @RestController 등의 애노테이션이 붙은 클래스를 찾아 빈으로 등록하게 됩니다.
package org.edwith.webbe.calculatorcli;
import org.springframework.stereotype.Component;
@Component
public class CalculatorService {
public int plus(int value1, int value2) {
return value1 + value2;
}
public int minus(int value1, int value2) {
return value1 - value2;
}
public int multiple(int value1, int value2) {
return value1 * value2;
}
public int divide(int value1, int value2) throws ArithmeticException {
return value1 / value2;
}
}
스프링 빈 컨테이너에 빈으로 등록하여 컨테이너가 관리한다는 것은 개발자가 직접 인스턴스를 생성하지 않는다는 것을 의미합니다.(IoC / DI) 스프링 빈 컨테이너가 인스턴스를 생성해서 관리한다는 것을 의미하는데요. 스프링 빈 컨테이너가 CalculatorService 클래스를 찾아 빈으로 등록할 수 있도록 빈으로 지정하고 싶은 클래스 위에 @Component 애노테이션을 붙입니다.
package org.edwith.webbe.calculatorcli;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args){
// ApplicationConfig.class 설정파일을 읽어들이는 ApplicationContext객체를 생성합니다.
// 아래 한줄이 실행되면서 컴포넌트 스캔을 하고, 컴포넌트를 찾으면 인스턴스를 생성하여 ApplicationContext가 관리하게 됩니다.
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfig.class);
// ApplicationContext가 관리하는 CalculatorService.class타입의 객체를 요청합니다.
CalculatorService calculatorService = applicationContext.getBean(CalculatorService.class);
// ApplicationContext로 부터 받은 객체를 잉요하여 덧셈을 구합니다.
System.out.println(calculatorService.plus(10, 50));
}
}
이제 Bean 공장도 만들었고 Bean 으로 생성할 대상도 지정이 끝났습니다. 이제 실제로 사용하는 Main 클래스를 만들어보겠습니다. 위 코드의 실행 결과는 60이 출력됩니다.
이전 JUnit 테스트 코드에서는 Spring Framework 로 Bean 을 생성해서 관리하지 않았기 때문에 @Before 애노테이션이 붙은 init( ) 메서드에서 CalculatorService 인스턴스를 개발자가 직접 초기화시켜준 것을 확인할 수 있습니다. 스프링 빈 컨테이너가 빈을 생성하고 관리하도록 하고, 그 빈을 테스트할 것이기 때문에 위의 소스 코드를 다음과 같이 수정합니다.
package org.edwith.webbe.calculatorcli;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ApplicationConfig.class})
public class CalculatorServiceTest {
@Autowired
CalculatorService calculatorService;
@Test
public void plus() throws Exception{
// given
int value1 = 10;
int value2 = 5;
// when
int result = calculatorService.plus(value1, value2);
// then
Assert.assertEquals(result, 15); // 결과와 15가 같을 경우에만 성공
}
@Test
public void divide() throws Exception{
// given
int value1 = 10;
int value2 = 5;
// when
int result = calculatorService.divide(value1, value2);
// then
Assert.assertEquals(result, 2); // 결과와 15가 같을 경우에만 성공
}
@Test
public void divideExceptionTest() throws Exception{
// given
int value1 = 10;
int value2 = 0;
try {
calculatorService.divide(value1, value2);
}catch (ArithmeticException ae){
Assert.assertTrue(true); // 이부분이 실행되었다면 성공
return; // 메소드를 더이상 실행하지 않는다.
}
Assert.assertTrue(false); // 이부분이 실행되면 무조건 실패다.
}
}
@RunWith(SpringJUnit4ClassRunner.class) 애노테이션을 테스트 클래스 위에 붙입니다. @RunWith 애노테이션은 JUnit 이 제공하는 애노테이션인데요. @RunWith 애노테이션은 JUnit 이 테스트 코드를 실행할 때 스프링 빈 컨테이너가 내부적으로 생성되도록 합니다. 그 다음으로 @ContextConfiguration(classes = {ApplicationConfig.class}) 은 내부적으로 생성된 스프링 빈 컨테이너가 사용할 설정파일을 지정할 때 사용합니다. 말이 어려운데 결국 이 두 애노테이션을 사용하는 궁극적인 이유는 Bean 컨테이너 환경을 불러와서 @Autowired 를 사용할 수 있게 하는 것입니다.
이렇게 해서 스프링 빈 컨테이너에서 관리되는 Bean 을 JUnit 테스트에서 사용하는 방법에 대해서 배웠습니다.