
테스트 코드를 작성하다보면 아래와 같이 중복되는 코드를 작성할 때가 있다.
@Test
@DisplayName("멤버의 이름이 2자 미만이라면 예외를 발생시킨다.")
void validateMemberNameLengthNotLessThanTwo() {
// given
String name = "1";
// when, then
assertThatThrownBy(() -> new Member(name))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("사용자의 이름의 길이가 적절하지 않습니다.");
}
@Test
@DisplayName("멤버의 이름이 10자를 초과한다면 예외를 발생시킨다.")
void validateMemberNameLengthNotMoreThanTenTen() {
// given
String name = "sopt33thchannamgung";
// when, then
assertThatThrownBy(() -> new Member(name))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("사용자의 이름의 길이가 적절하지 않습니다.");
}
@Test
@DisplayName("멤버의 이름이 숫자를 포함하지 않는다면 예외를 발생시킨다.")
void validateMemberNameIncludeNumber() {
// given
String name = "akmu";
// when, then
assertThatThrownBy(() -> new Member(name))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("사용자의 이름 형식이 적절하지 않습니다.");
}
위 코드는 모두 멤버의 이름을 테스트하는 메서드이다.
여러가지 상황에 대해 테스트를 진행하려다 보니 중복된 코드도 많고 가독성도 좋지 않다.
이를 해결할 수 있는 방법이 있을까? 없으면 이 글을 쓰지도 않았다.
있다.
@ParameterizedTest는 여러 개의 테스트를 한 테스트 코드에서 실행할 수 있도록 한다.
위 코드를 @ParameterizedTest를 이용해 작성하면 아래와 같이 작성할 수 있다.
@ParameterizedTest
@DisplayName("멤버의 이름이 조건에 맞지 않는다면 예외를 발생시킨다.")
@ValueSource(strings = {"1", "sopt33thchannamgung", "akmu"})
void validateMemberName(String name) {
// when, then
assertThatThrownBy(() -> new Member(name))
.isInstanceOf(IllegalArgumentException.class);
}
여러 테스트 케이스를 한 번에 테스트함을 통해 중복된 코드를 확 줄이고 가독성도 좋아진 모습을 확인할 수 있다.
@ParameterizedTest의 사용법을 더 익혀보자.
@ValueSource는 한 가지 형식의 값으로 여러 번의 테스트를 진행할 때 사용한다.
아래의 값들에 적용 가능하다.

사용법은 위 예제와 같다.
@CsvSource는 다수의 값들로 여러 번의 테스트를 진행할 때 사용한다.
아래 예제를 확인해보자.
@Test
@DisplayName("200%는 악동뮤지션의 앨범 [PLAY]의 타이틀곡이다.")
void checkPLAY() {
// given
String song = "200%";
String album = "PLAY";
// when
Akmu akmu = new Akmu(song);
String result = akmu.getType();
// then
assertThat(result).isEqualTo(album);
}
@Test
@DisplayName("RE-BYE는 악동뮤지션의 앨범 [사춘기 상(思春記 上)]의 타이틀곡이다.")
void checkREBYE() {
// given
String song = "RE-BYE";
String album = "사춘기 상";
// when
Akmu akmu = new Akmu(song);
String result = akmu.getType();
// then
assertThat(result).isEqualTo(album);
}
@Test
@DisplayName("오랜 날 오랜 밤은 악동뮤지션의 앨범 [사춘기 하 (思春記 下)]의 타이틀 곡이다.")
void check오랜날오랜밤() {
// given
String song = "오랜 날 오랜 밤";
String album = "사춘기 하";
// when
Akmu akmu = new Akmu(song);
String result = akmu.getType();
// then
assertThat(result).isEqualTo(album);
}
@Test
@DisplayName("어떻게 이별까지 사랑하겠어, 널 사랑하는 거지는 악동뮤지션의 앨범 [항해]의 타이틀 곡이다.")
void check어떻게이별까지사랑하겠어널사랑하는거지() {
// given
String song = "어떻게 이별까지 사랑하겠어, 널 사랑하는 거지";
String album = "항해";
// when
Akmu akmu = new Akmu(song);
String result = akmu.getType();
// then
assertThat(result).isEqualTo(album);
}
위 예제는 입력 값과 출력 값을 가지고 테스트를 진행하고 있다.
@CsvSource를 사용하면 위 예제를 아래와 같이 나타낼 수 있다.
@ParameterizedTest
@DisplayName("악동뮤지션의 노래를 입력 받고 그에 맞는 앨범을 나타낼 수 있다.")
@CsvSource(value = {"200%, PLAY", "RE-BYE, 사춘기 상", "오랜 날 오랜 밤, 사춘기 하", "어떻게 이별까지 사랑하겠어 널 사랑하는 거지, 항해"})
void checkAkmuSong(String song, String album) {
// when
Akmu akmu = new Akmu(song);
String result = akmu.getType();
// then
assertThat(result).isEqualTo(album);
}
@NullSource와 @EmptySource를 합친 것으로, null 값과 empty 값을 가지고 테스트를 진행한다.
@ParameterizedTest
@DisplayName("null 값 또는 empty 값이 입력되면 알 수 없음으로 설정된다.")
@NullAndEmptySource
void checkNullAndEmpty(String song) {
// given
String album = "알 수 없음";
// when
Akmu akmu = new Akmu(song);
String result = akmu.getType();
// then
assertThat(result).isEqualTo(album);
}

위와 같이 null 값과 empty 값을 이용해 테스트를 하는 것을 확인할 수 있다.
@EnumSource는 Enum 클래스의 테스트를 도와준다. 예제는 아래와 같다.
@ParameterizedTest
@DisplayName("악동뮤지션 음악의 앨범을 확인할 수 있다.")
@EnumSource(value = AkmuSong.class, names = {"LoveLee", "후라이의꿈"})
void checkAkmuSong(AkmuSong song) {
// given
String album = "Love Lee";
// when, then
assertThat(song.getAlbum()).isEqualTo(album);
}
value에 테스트에 사용할 Enum class를 지정해준다.
만약 특정 값만 사용하고 싶은 경우 names에 사용할 값들을 넣어준다.
@MethodSource는 메서드에서 반환하는 값들로 여러 번의 테스트를 진행할 때 사용한다.
@MethodSource 안에 메서드 이름을 적어준다. 이 때 메서드의 이름과 테스트 메서드의 이름을 같게 한다면 이를 생략할 수 있다.
메서드는 Arguments의 Stream을 반환해야 한다.
예제는 아래와 같다.
@ParameterizedTest
@DisplayName("입력된 노래와 비교하여 악동뮤지션 노래의 개수를 반환한다.")
@MethodSource("provideAllCasesSongs")
void countAkmuSongs(List<String> songs, int expectedResult) {
// given
Akmu akmu = new Akmu();
// when
int result = akmu.checkAkmuSong(songs);
// then
assertThat(result).isEqualTo(expectedResult);
}
private static Stream<Arguments> provideAllCasesSongs() {
return Stream.of(
Arguments.of(List.of("OMG", "Drama", "200%"), 1),
Arguments.of(List.of("200%", "RE-BYE", "오랜 날 오랜 밤"), 3)
);
}
이처럼 @ParameterizedTest를 통해 더 질좋은 테스트 코드를 작성할 수 있다.