다소 늦은 프리코스 2주 차 후기를 올립니다! 현재 진행 중인 미션이 꽤 걸리는지라 이제야 올리게 됐네요 🥲
이번 미션은 학교 선배 분께 리뷰를 받으며 미리 해 본 자동차 경주 미션이었습니다. 그렇기에 1주 차 때처럼 핵심 로직은 쉽게 이해되었었습니다.
JUnit5에 대해 깊게 파보게 됨 (ParameterResolutionException)
이번 미션에서는 요구사항으로 테스트를 해 보라는 것이 아예 요구사항에 정의되어 있었습니다. 그래서 우아한 테크코스의 단위 테스트 테코톡 영상을 보며 제대로 테스트를 익혀보고 싶었고, 이 과정에서 @ParameterizedTest를 쓰면 같은 테스트이면서 다른 입력값을 검증할 경우를 축약할 수 있음을 배웠습니다.
그런데 우연히 @Test와 @ParameterizedTest를 함께 사용했었는데, 이 과정에서 ParameterResolutionException이라는 예외를 접했습니다. 이들을 함께 쓰면 예외가 발생하는 것임을 쉽게 알았지만, 왜 정확히 이러한 예외가 발생한 것인지를 알고 싶어 JUnit의 내부 코드를 디버깅해 보며 원인을 찾고자 하였습니다. 그 결과 @Test의 경우에서는 @ParameterizedTest에서 사용하던 것처럼 String 형태의 인자가 주어질 경우 지원되는 파라미터 리졸버가 없기 때문에 예외가 발생함을 알게 되었습니다. 자세한 내용은 이 글을 참고해 주시면 됩니다!
레코드 도입
저번 주차 미션인 숫자 야구에서는 DTO를 사용하지 않아도 괜찮을 것 같아 아예 작성하지 않았었지만, 이번 자동차 경주 미션 같은 경우에는 매번 자동차의 각 현황을 보여주어야 해서 DTO를 사용하였습니다. 그러던 도중 자바 17의 특징인 레코드는 무엇인지 문득 궁금증이 들었고, 막상 개념을 접하니 기존에 직접 작성하던 DTO를 쉽게 대체할 수 있겠다고 판단되어 DTO 코드를 레코드로 바꿨습니다. 이렇듯 자바 버전에 따라 지원 가능한 개념들이 있기에, 그동안 자바 버전에 대해 크게 신경 쓰지 않던 게 얼마나 좋지 않은지를 느꼈고 앞으로는 프로그램에 사용되는 버전에 따라서 어떤 것들을 쓸 수 있을지 미리 조사해 봐야겠다는 생각을 가지게 되었습니다. 레코드에 대한 글은 이 글을 참고해 주시면 됩니다.
JUnit의 Assertions 메서드에 대해 더 알게 됨
숫자 야구 미션에서는 테스트 코드 작성 시, 예외 발생과 정상 코드를 아래처럼 작성했었습니다.
@Test
void 플레이_숫자는_중복되면_안된다() {
// given & when
Throwable exception = Assertions.assertThrows(IllegalArgumentException.class, () -> {
PlayNumber playNumber = PlayNumber.from("111");
});
// then
assertThat(exception.getMessage()).isEqualTo(PLAY_NUMBER_DUPLICATE_EXCEPTION.toString());
}
@Test
void 세자리_모두_정상이라면_문제없이_생성된다() {
PlayNumber playNumber = PlayNumber.from("123");
}
Assertions 메서드들을 더 찾아보니, 다음과 같은 적절한 메서드들을 찾을 수 있었습니다.
- org.assertj.core.api.Assertions.assertThatThrownBy: 특정 예외가 발생하는지, 그리고 예외 메시지가 특정 메시지가 맞는지 등을 검증할 수 있습니다.
- org.junit.jupiter.api.Assertions.assertDoesNotThrow: 예외가 터지지 않고 정상적으로 진행이 되는지에 사용할 수 있습니다.
이후 아래와 같은 방식으로 적용하였습니다.
@Test
@DisplayName("이름이 모두 독립적이면 정상 생성된다.")
void splitNamesTest() {
// when & then
assertDoesNotThrow(() -> Names.from("john,bob,alice"));
}
@Test
@DisplayName("같은 이름이 발견되면 예외가 발생한다.")
void duplicateNamesExceptionTest() {
// when & then
assertThatThrownBy(() -> Names.from("john,john,bob")).isInstanceOf(IllegalArgumentException.class)
.hasMessage(DUPLICATE_NAME_EXCEPTION.getMessage());
}
- assertDoesNotThrow를 통해 확실히 정상적으로 실행이 되는지 검증의 의미를 전달할 수 있게 되었습니다.
- assertThatThrownBy를 통해 검증 과정을 한 번에 표현할 수 있게 되었습니다.
이렇게 Assertions에서 제공하는 메서드들을 활용하니 더 직관적이고 검증의 의미를 부여할 수 있어 한 층 더 좋아진 코드임을 느꼈습니다.
Assertions에 관해서는 다른 글에서 더 정리해 보도록 하겠습니다.
모호한 요구사항에 대한 고민
코치와의 수다 타임 (코수타) 때 이런 말씀을 해주셨습니다.
실제로 개발에 투입되면 심한 경우에는 기획과 개발이 동시에 일어나기도 한다.
우리가 김치볶음밥을 요리할 때 김치를 정확히 얼마나, 고춧가루를 정확히 얼마나 넣을지는 고려하지 않는다.
이러한 과정에 대해서도 연습해 보길 권한다.
위 말씀처럼, 그동안 진행했던 프로젝트들에서도 이렇게 기획과 동시에 개발을 해야 했던 적이 있곤 하였습니다.
자동차 경주 미션의 경우에도 자동차의 이름을 입력받을 때 5자 이하인 것만 조건으로 되어 있어서, 공백이 포함돼도 되는지, 숫자가 들어가도 되는지와 같은 세부적인 예외사항에 대해서는 기술해두지 않았습니다. 그래서 아예 회사에서 실제로 이 미션을 개발해야 한다면 내부적으로 이러한 논의들이 이미 진행됐다고 가정하고, 제 나름의 기준을 세워 예외처리를 해 두었습니다.
프리코스도 그렇고 실제 개발도 그렇고 시간이 지날수록, 또는 때로는 이렇게 모호한 요구사항들이 더 많은 게 있을 것입니다. 그런 점에서 이러한 고민을 미리 해 볼 수 있었다는 점에서, 많은 것을 배운 것 같습니다.
결론
저번 주차에는 구조적인 것에 대해 고민을 했었다면, 이번 주에는 기술에 관해 고민을 한 것 같습니다. 다음 프리코스 미션에서도 더 많은 것을 배울 수 있으면 좋겠습니다 😃
최종 제출
이곳에서 확인하실 수 있습니다.
'🚀 우아한테크코스 6기 지원 기록' 카테고리의 다른 글
[프리코스] 프리코스 4주차 후기 (크리스마스 프로모션 🎄) (1) | 2023.11.17 |
---|---|
[프리코스] 프리코스 3주차 후기 (로또 🎱) (0) | 2023.11.14 |
[프리코스] 프리코스 1주차 후기 (숫자 야구 ⚾️) (1) | 2023.10.31 |