드디어 JUnit의 시대가 끝이 나는것인가.... 라는 생각이 드는 멋진 테스트 Framework인 Spock를 소개합니다.
groovy 언어로 구성을 해야지 되는 언어적 제약사항이 있지만, 기존의 JUnit Test에 비해서 매우 간결한 문법과 TDD를 위한 구성을 제공하고 있습니다.
1. 설정
gradle 기준으로 spock는 다음과 같이 설정됩니다.
repositories { mavenCentral() maven { url "http://oss.sonatype.org/content/repositories/snapshots/" } } dependencies { groovy "org.codehaus.groovy:groovy-all:2.1.5" testCompile "org.spockframework:spock-core:1.0-groovy-2.0-SNAPSHOT" }
기본적으로 JUnit을 사용하고 있는 test project입니다.
2. 구성
기본적으로 JUnit과 거의 유사한 기본 설정을 갖습니다.
Spock | JUnit |
Specification | Test class |
setup() | @Before |
cleanup() | @After |
setupSpec() | @BeforeClass |
cleanupSpec() | @AfterClass |
Feature | Test |
Parameterized feature | Theory |
Condition | Assertion |
Exception condition | @Test(expected=...) |
@FailsWith | @Test(expected=...) |
Interaction | Mock expectation (EasyMock, JMock, ...) |
3. 테스트 코드의 종류에 따른 구현
우리가 일반적으로 테스트 코드를 짤때, 다음과 테스트 코드가 주로 작성되게 됩니다.
1) 특정한 method를 실행후, 객체의 상태가 예측대로인지 확인
2) 특정한 method의 input을 선정하고, output값이 예측대로 나왔는지 확인
이 두가지 case는 약간은 미묘하게 다릅니다. 1)의 경우는 response를 확인을 하는 것이고, 2)의 결과는 예측하는 것으로 약간의 차이를 가지고 오게 됩니다.
이를 spock에서는 여러 block으로 지정하여, case에 대한 내용을 명확하게 하고 있습니다.
spock에서 지원하는 block은 다음과 같습니다. 또한 이 block뒤에는 자유롭게 문자열을 넣어서, block안의 내용을 서술할 수 있습니다.
setup : 객체에 대한 설정
when / then : when block이 있으면 반드시 then block이 존재합니다. when에서 객체의 response를 얻어내고, then을 통해 response를 확인합니다. condition을 설정한다고 생각하시면 편합니다.
expect / where : 예측되는 값과 예측값 list를 정의합니다. spock에서 가장 놀라운 기능중 하나입니다.
위 block을 적용한 code example은 다음과 같습니다.
def "건물이름 길이가 작아 exception이 발생"() { def buildingName = "가" when: service.searchByBuilding(buildingName) then: def e = thrown(IllegalArgumentException) e.message == AddressSearchServiceImpl.BUILDING_NAME_IS_TOO_SHORT } def "서울내의 레미안만 얻어오기"() { def buildingName = "레미안" when: def searchResults = service.searchByBuilding(SidoEnum.SEOUL.getStringValue(), buildingName, 0, 10) then: searchResults.every { r -> r.buildingName.contains(buildingName) r.siGunGu.sido.sidoNumber.equals(SidoEnum.SEOUL.getStringValue()) == true } }
def "검색문자열 분리 테스트"() { expect: def matcher = SearchTextRegex.extractSearchText(input) matcher.find() == true matcher.group("mainText").equals(mainText) == true matcher.group("mainNumber").equals(mainNumber) == true where: input | mainText | mainNumber "구로동 245 번지" | "구로동" | "245" "서초1동" | "서초1동" | "" "잠실동 624" | "잠실동" | "624" "지봉로 1" | "지봉로" | "1" }
너무나 멋지지 않나요? 지금까지 구성하던 test code의 길이가 절반 이하로 줄어들뿐 아니라, 매우 직관적이고, TDD에 적합한 테스트 코드 형태로 구성이 되고 있는 것을 알 수 있습니다.
개인적으로 하고 있는 project들을 모두 spock로 변경하는 작업을 한번 해봐야지 될 것 같습니다. 이런 것을 보면 왠지 희열이 느껴지지 않나요? ^^;;
모두들 Happy Coding~