-
학습 테스트와 단위 테스트Language/Java 2020. 7. 20. 22:02
우아한테크코스(이하 우테코) 레벨 1 복습을 위한 글입니다.
우테코에서는 TDD를 강조합니다.
첫 주 수업에서 배웠던 내용도 테스트에 대한 내용입니다.
관련 내용을 간단하게 복습해보겠습니다.
학습 테스트란.
기능 구현을 위한 테스트라기보다 API, 라이브러리, 프레임워크가 어떻게 동작하는지를 검증하기 위한 테스트입니다.
학습 테스트의 장점.
- 다양한 조건에 따른 기능을 손쉽게 확인해 볼 수 있습니다.
- 학습 테스트 코드를 개발 중에 참고할 수 있습니다.
- 프레임워크나 제품을 업그레이드할 때 호환성 검증을 보여줍니다. (유지 보수에 도움을 줍니다.)
- 테스트 작성에 대한 좋은 훈련이 됩니다.
- 출처
학습 테스트로 배우는 스프링 - SpringWiki
프레임워크나 다른 라이브러리 등에 대한 테스트를 학습테스트(learning test) 라고 한다. ### 학습 테스트의 장점 다양한 조건에 따른 기능을 손쉽게 확인해 볼 수 있다. 학습 테스트 코드를 개발 중
springwiki.readthedocs.io
예시와 함께 학습 테스트를 설명해보겠습니다.
public class SetTest { private Set numbers; @BeforeEach void setUp() { numbers = new HashSet<>(); numbers.add(1); numbers.add(1); numbers.add(2); numbers.add(3); } @DisplayName("size test") @Test void size() { Assertions.assertEquals(numbers.size(), 3); } @DisplayName("contains test") @ParameterizedTest @CsvSource(value = {"0:false", "1:true", "2: true", "3:true", "4:false"}, delimiter = ':') void contains_has_return_true_not_return_false(int index, boolean expected) { assertThat(numbers.contains(index)).isEqualTo(expected); } }
위의 코드는 자바에서 기본적으로 제공하는
Set
컬렉션에 대한 학습 테스트 입니다.Set
에서 제공하는size
와contains
메서드를 테스트합니다.앞서 설명한 학습 테스트의 장점을 상기해보겠습니다.
contains_has_return_true_not_return_false
메서드를 통해 다양한 조건에 따른 contains 메서드의 기능을 쉽게 확인해 볼 수 있습니다.
그리고 개발을 진행하며 테스트 코드를 참고하여size
나contains
메서드를 활용하는 방법을 참고할 수 있습니다.
마지막으로 (가능성이 정말 낮지만 API 구현이 변경되어)size
나contains
메서드가 반환하는 값에 변동이 있을 시 테스트가 정상 동작하지 않을 수 있기에 호환성 검증을 할 수 있습니다.
단위 테스트(Unit Test)란.
프로덕션 코드를 구현한 후
JUnit
과 같은 도구를 활용해 작은 단위를 테스트하는 것을 의미합니다.
단위 테스트와 TDD는 다른 개념입니다.보다 쉬운 이해를 위해 프로덕션 코드를 예시로 들겠습니다.
public enum OperatorType { PLUS("+", Double::sum), MINUS("-", (firstOperand, secondOperand) -> firstOperand - secondOperand), DIVIDE("/", (firstOperand, secondOperand) -> firstOperand / secondOperand), MULTIPLY("*", (firstOperand, secondOperand) -> firstOperand * secondOperand); private String operator; private BinaryOperator<Double> expression; OperatorType(String operator, BinaryOperator<Double> expression) { this.operator = operator; this.expression = expression; } public static OperatorType from(final String operator) { return Arrays.stream(OperatorType.values()) .filter(value -> value.operator.equals(operator)) .findFirst() .orElseThrow(() -> new IllegalArgumentException("연산자에 포함되지 않습니다.")); } }
해당 코드는 계산기 프로그램에 사용하는 OperatorType Enum입니다.
from
이라는 정적 팩토리 메서드를 이용하여 일치하는OperatorType
을 반환하는 기능을 제공합니다.단위 테스트는 바로 이
from
이라는 메서드가 잘 동작하는지 테스트하는데 활용됩니다.public class OperatorTypeTest { @DisplayName("from 정적 팩토리 메서드 정상 동작 테스트") @ParameterizedTest @ValueSource(strings = {"+", "-", "/", "*"}) void from_normal_cals_test(String value) { Assertions.assertThat(OperatorType.from(value)) .isInstanceOf(OperatorType.class); } @DisplayName("from 정적 팩토리 메서드 예외처리 테스트") @ParameterizedTest @ValueSource(strings = {"1", "**", "x", "\\", "s"}) void from_should_throw_exception_when_invalid_input(String value) { Assertions.assertThatThrownBy(() -> { OperatorType.from(value); }).isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("연산자에 포함되지 않습니다."); } }
from_normal_cals_test
메서드는 정적 팩토리 메서드가 정상적으로 동작하는지 테스트합니다. 테스트 방법으로는from
을 이용해 생성한 객체가OperatorType
클래스의 인스턴스가 맞는지 확인합니다.
그리고from_should_throw_exception_when_invalid_input
메서드는 정적 팩토리 메서드가 정상적으로 예외 상황을 처리하는지 테스트합니다. 테스트 방법으로는from
메서드에서 지정해둔IllegalArgumentException
이 메시지와 함께throw
되는지 확인합니다.보통 테스트 코드는 테스트하고 싶은 파일명 뒤에
Test
를 붙인 클래스를 생성해서 진행합니다.
프로덕션 코드가main 패키지
에 있다면 테스트 코드는test 패키지
에 위치합니다.잘 작성된 단위 테스트가 프로그램의 완벽함을 보장하지는 않습니다. 그렇지만 새로운 요구 사항에 따라 리팩토링을 진행할 시 예상치 못한 변경사항이 생긴다면 이를 확인할 수 있는 방법을 제공합니다. 현재 진행중인 칵테일픽 프로젝트에서도 필요한 부분에 대해서 똑똑한 단위테스트를 작성하려고 팀원들 모두가 노력중입니다!
'Language > Java' 카테고리의 다른 글
Java의 Error와 Exception 그리고 예외처리 전략 (1) 2020.09.17 String과 StringBuilder (0) 2020.08.02 Production Code & Test Code & JUnit (0) 2020.07.09