ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 학습 테스트와 단위 테스트
    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에서 제공하는 sizecontains 메서드를 테스트합니다.

    앞서 설명한 학습 테스트의 장점을 상기해보겠습니다.
    contains_has_return_true_not_return_false 메서드를 통해 다양한 조건에 따른 contains 메서드의 기능을 쉽게 확인해 볼 수 있습니다.
    그리고 개발을 진행하며 테스트 코드를 참고하여 sizecontains 메서드를 활용하는 방법을 참고할 수 있습니다.
    마지막으로 (가능성이 정말 낮지만 API 구현이 변경되어) sizecontains 메서드가 반환하는 값에 변동이 있을 시 테스트가 정상 동작하지 않을 수 있기에 호환성 검증을 할 수 있습니다.

     


     

    단위 테스트(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

    댓글

Toneyparky Blog