Spock 프레임워크의 @Unroll과 where 절 사용하기
1. 문제 상황
최근 프로젝트에서 Role 이라는 Enum 클래스를 만들면서 of 메서드를 추가하게 되었다.
이 메서드는 문자열 입력값을 받아 Enum 값을 반환하는 역할을 한다.
package com.griotold.auth.domain.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum Role {
MASTER("ROLE_MASTER"),
HUB("ROLE_HUB"),
DELIVERY("ROLE_DELIVERY"),
COMPANY("ROLE_COMPANY");
private final String role;
public static Role of(String request) {
if (request == null) {
return null;
}
return switch (request.toUpperCase()) {
case "MASTER" -> MASTER;
case "HUB" -> HUB;
case "DELIVERY" -> DELIVERY;
case "COMPANY" -> COMPANY;
default -> null;
};
}
}
여기서 핵심은 대소문자 구분 없이 문자열이 들어와도 올바른 Role Enum 값을 반환해야 한다는 점이었다.
현 프로젝트는 Spock 이라는 테스트 프레임워크를 사용하고 있다.
2. 테스트 코드 작성
of 메서드가 올바르게 동작하는지 테스트 코드를 작성해보자.
특히, 여러 입력값을 한 번에 테스트하기 위해 where: 절을 사용했다.
package com.griotold.auth.domain.enums
import spock.lang.Specification
import spock.lang.Unroll
class RoleTest extends Specification {
@Unroll
def "of 메서드가 대소문자 상관없이 올바른 Role을 반환해야 한다"() {
expect:
Role.of(input) == expectedRole
where:
input || expectedRole
"MASTER" || Role.MASTER
"master" || Role.MASTER
"MaStEr" || Role.MASTER
"HUB" || Role.HUB
"hub" || Role.HUB
"Hub" || Role.HUB
"DELIVERY" || Role.DELIVERY
"delivery" || Role.DELIVERY
"COMPANY" || Role.COMPANY
"company" || Role.COMPANY
}
@Unroll
def "of 메서드가 유효하지 않은 입력값에 대해 null을 반환해야 한다"() {
expect:
Role.of(input) == null
where:
input << [null, "", "INVALID", "123", "ROLE_MASTER"]
}
}
3. @Unroll의 역할
테스트 코드를 작성하면서 @Unroll 어노테이션을 처음 접했다.
처음에는 없어도 테스트가 정상 실행되었기 때문에 큰 차이를 느끼지 못했다.
하지만 @Unroll을 사용하면 테스트 실행 결과에서 개별 입력값이 명확하게 출력되며,
실패 시 어떤 값에서 문제가 발생했는지 바로 확인할 수 있다.
예를 들어, @Unroll을 적용한 테스트 실행 결과는 다음과 같다.
4. @Unroll 을 활용해 가독성 높이기
@Unroll에 문자열을 추가하면, Test Results 의 가독성을 높일 수 있다.
package com.griotold.auth.domain.enums
import spock.lang.Specification
import spock.lang.Unroll
class RoleTest extends Specification {
// 문자열 추가!
@Unroll("입력값 #input 일 때, 예상 결과는 #expectedRole 이어야 한다")
def "of 메서드가 대소문자 상관없이 올바른 Role을 반환해야 한다"() {
expect:
Role.of(input) == expectedRole
where:
input || expectedRole
"MASTER" || Role.MASTER
"master" || Role.MASTER
"MaStEr" || Role.MASTER
"HUB" || Role.HUB
"hub" || Role.HUB
"Hub" || Role.HUB
"DELIVERY" || Role.DELIVERY
"delivery" || Role.DELIVERY
"COMPANY" || Role.COMPANY
"company" || Role.COMPANY
}
// 문자열 추가!
@Unroll("입력값 #input 일 때, 예상 결과는 null 이어야 한다")
def "of 메서드가 유효하지 않은 입력값에 대해 null을 반환해야 한다"() {
expect:
Role.of(input) == null
where:
input << [null, "", "INVALID", "123", "ROLE_MASTER"]
}
}
위 처럼, 문자열을 추가하면 좀 더 가독성을 높일 수 있다.
4. 결론
Spock에서 where 절을 활용하면 여러 테스트 케이스를 깔끔하게 작성할 수 있고,
@Unroll을 사용하면 실행 결과를 더욱 직관적으로 확인할 수 있다.
앞으로도 데이터 기반 테스트를 작성할 때 적극 활용할 계획이다.
References
https://blog.leocat.kr/notes/2019/05/01/spock-unroll-the-parameterized-tests#google_vignette