> SpringBoot – JUnit 파라미터 반복 테스트
JUnit 테스트 기동을 위한 Spring 관련 환경설정 어노테이션은 어려가지가 있다. 그러나 환경 셋팅의 심플함을 주무기로 하는 SpringBoot의 강점 활용을 위해 여러 어노테이션들에 대한 학습 보다는 가능한 간단하게 설정 후 테스트를 진행할 수 있는 방법을 알아보려 한다. 동일한 Request에 대한 테스트라 할지라도 고려해야하는 Input 항목이 많을 수록, 테스트 케이스는 승수적으로 늘어날 가능성이 있다. 바로 Input 값들의 조합 (파라미터)을 변경해가며 반복 테스트를 수행해야 하는 경우이다. 금융사들의 업무시스템의 경우 더욱 그러한 특징이 도드라지지 않나 싶다. SpringBoot – JUnit을 통해 해당 테스트를 수행하는 방법을 알아보고자 한다.
사족이지만, TDD를 정착시켜 개발문화 및 효율을 한단계 앞으로 나아가게 하려는 움직임이 국내에도 많이 있는 것 같다. 구태여 TDD를 꺼내지 않더라도, JUnit 등의 테스트 프레임웍의 활용은 금융 외의 다른 도메인에서는 그 중요성에 집중하는 개발자들이 많다. 그러나 금융사들의 IT부서 대부분에게 Java 환경으로의 전환은 단순한 개발언어의 변경 외의 의미가 없어 보인다. (특히 계정계) 내가 처음 금융개발을 시작하게된 시점과 테스트방법은 전혀 나아가지 못 한 것 같다.
일면 이해하는 면이 있다. 컴플라이언스 관련 개발이 많은 금융산업의 특성상 시간은 흘러가고 릴리즈 일자는 미룰 수 없다. 비즈니스 담당부서(고객)들은 IT 의존도가 높은 경우가 많고 또 미룰수 없는 릴리즈의 특징을 교묘히 악용하는 경우도 있다.(결국에는 그 날짜에 릴리즈하게 되니까) 이에 개발자들은 조금은 피해의식을 가지고 있다. 그렇기에 요구사항을 정제하고 테스트케이스를 미리 만들려는 의지를 얻기가 쉽지않다.
금융사의 IT개발, 운영 부서는 테스트의 중요성도 나름은 인식은 한다. 다만 더 나은 방법의 테스트에 대한 연구가 조금은 부족하고 도메인 지식 (금융업무 지식)을 가장 강조하면서도 테스트케이스의 작성은 결국 고객만의 역할이라는 인식, 그리고 마지막으로 변경 적용의 엄격함 / 비효율도 소스품질의 저하를 불러오는 악순환의 고리가 아닌가 싶다. 타국 이긴하지만, 역시 금융환경에서 우리와 비슷한 악조건을 이겨나가 결국 애자일, TDD를 정착시켰던 개발자의 [소프트웨어 장인]이란 책이 떠오른다.
> Dependency (Maven)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
위와 같이 [spring-boot-starter-test] 의존성 추가 하나만으로 JUnit, Mockito, Hamcrest 등의 테스트를 위한 lib의 사용이 SpringBoot 안에서 가능해진다.
운영 환경에서는 활용되지 않기에, 배포제외 및 테스트 클래스 패스에만 적용을 위해 <scope>test</scopt> Maven Option을 적용하였다.
> JUnit 반복 테스트 Code
@RunWith(Parameterized.class) @SpringBootTest public class EventCacheDAOSearchTest { @ClassRule public static final SpringClassRule springClassRule = new SpringClassRule(); @Rule public final SpringMethodRule springMethodRule = new SpringMethodRule(); private String subjcode; private String searchText; private int pageNo; private boolean freeOnly; @Autowired private EventCacheDAO eventCacheDAO; public EventCacheDAOSearchTest(String subjcode, String searchText, int pageNo, boolean freeOnly) { this.subjcode = subjcode; this.searchText = searchText; this.pageNo = pageNo; this.freeOnly = freeOnly; } @Parameterized.Parameters public static List parametersForSearch() { return Arrays.asList(new Object[][] { {"ALL","서초구", 1, false } ,{"ALL","서초구", 2, false } ,{"ALL","서초구", 1, true } ,{"ALL","연주회", 1, false } ,{"ALL","바이올린", 1, false } ,{"1","강남", 1, true } ,{"1","강남", 2, true } ,{"18","", 1, true } ,{"19","교육", 1, true } }); } //SQL SearchText, EhCache Search간 결과비교 @Test public void compareSearchTextMethod(){ List<Seoulevent> allEventList = eventCacheDAO.getEventsBySearchText(this.subjcode, this.searchText, this.pageNo, this.freeOnly); List<Seoulevent> allEventListCache = eventCacheDAO.getCacheEventsBySearchText(this.subjcode, this.searchText, this.pageNo, this.freeOnly); assertTrue(allEventList.size() == allEventListCache.size()); } }
- @RunWith(Parameterized.class) – 파라미터 반복테스트를 위한 어노테이션 사용이다. 테스트 Class의 생성자 인자를 통해 파라미터를 받아 인스턴스 변수를 이용한 테스트가 가능하게 해준다.
- @SpringBootTest – 해당 Test ClassPath가 속한 Project의 SpringBoot Application Config를 자동으로 Load하여 주며(application.properties 등), 테스트를 위한 일부 어노테이션 사용을 가능하게 해준다. 웹서버가 포함된 SpringBoot의 특징을 활용해 웹서버 기동 환경을 만들어주기도 한다. [ (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)]
SpringBoot가 아닌 Spring에서의 @ContextConfiguration, @SpringApplicationConfiguration 를 대체한다. - @ClassRule, @Rule (선언된 멤버) – Test Class의 기준을 정하는 JUnit 어노테이션이다. 위의 선언된 문장은 2문장을 함께 사용할 경우 @RunWith(SpringRunner.class)를 대체 한다. @RunWith(SpringRunner.class or SpringJUnit4ClassRunner.class) 는 @RunWith는 JUnit 내장된 runner 대신 SpringJUnit4ClassRunner.class 클래스를 참조하여 테스트를 실행하도록 해준다. Bean 등을 위한 Spring의 여러 Container를 일반적인 Load 시점과 마찬가지로 기동하는데 그 목적이 있다. @RunWith는 다중 인자를 허용하지 않는다. 그렇기에 부득이 하게 Parameterized.class를 사용하기 위하여 위와 같이 선언하였다.
- @Parameterized.Parameters – 파라미터 정의를 위한 어노테이션이다. 해당 어노테이션이 선언된 메서드는 List형으로 파라미터를 반환한다. List item의 멤버 순서대로 해당 파라미터들은 본 Class 생성자에 주입된다. 그러므로 생성자를 그에 맞게 선언하여 파라미터를 해당 클래스의 인스턴스 멤버에 입력하는 등에 처리가 필요하다. List의 멤버 Size (갯수) 만큼 @Test 어노테이션이 붙은 메소드들이 반복 수행된다.
- 예로 보여진 위의 코드는 결과가 같다고 추정되는 2가지의 메소드를, 입력값 변화 반복테스트를 통해 결과를 비교하여 검증하는 테스트이다.