TDD - step 01

불순분자들·2022년 10월 26일
0

TDD

목록 보기
1/2

TDD


TDD는 Test-Driven-Development 의 약자로 테스트 주도 개발이라고 한다.

TDD를 해야하는 상황과 이유

TDD는 불확실성이 높을 때 '피드백'과 '협력'이 중요하다는 이유로 테스트 주도 개발을 하면 더 좋은 결과가 나올 수 있다.

"test"가 명사가 된다면 공유가 쉬워진다. 다른 사람의 코드를 쉽게 접근가능하게하고, 이해가 빨라진다.
그러므로, 다른 사람의 코드 의도를 확인할 수 있게 된다.

  • 처음해보는 프로그램 주제 !
  • 고객의 요구조건이 바뀔 수 있는 프로젝트 !
  • 개발하는 중에 코드를 많이 바꿔야 된다고 생각하는 경우 !
  • 내가 개발한 코드를 누가 유지보수할지 모르는 경우 !

TDD 개발 방식의 장점

  • 튼튼한 객체 지향적인 코드 생산 : TDD는 코드의 재사용 보장을 명시하므로 TDD를 통한 소프트웨어 개발 시 기능 별 철저한 모듈화가 이뤄진다.

  • 재설계 시간의 단축 : 테스트 시나리오를 작성하면서 다양한 예외를 생각하게 되는데 이는 개발 진행 중 소프트웨어의 전반적인 설계가 변경되는 일을 방지할 수 있다.

  • 디버깅 시간의 단축 : 어디서 발생하는 오류인지 유닛 테스트를 통해 특정 오류를 쉽게 찾아낼 수 있다.

  • 추가 구현의 용이함 : TDD의 경우 자동화된 유닛 테스팅을 전제하므로 테스트 기간을 획기적으로 단축시킬 수 있다.

String 클래스 요구사항 1


1,2을 ,로 split() 했을 때 1과 2로 잘 분리되는지 확인하는 학습 테스트를 구현한다.

1을 ,로 split() 했을 때 1만을 포함하는 배열이 반환되는지에 대한 학습 테스트를 구현한다.

@Test
    @DisplayName("요구사항 1")
    void split() {
        String str1 = "1,2";

        String[] arrStr1 = str1.split(",");

        assertThat(arrStr1).contains("1","2");
        assertThat(arrStr1).containsExactly("1","2");
    }

assertj의 contains()

순서와 상관 없이 실제 그룹이 주어진 값들을 포함하는지를 테스트하는 메서드

assertj의 containsExactly()

순서를 고려해 실제 그룹지 주어진 값을 포함하는지를 테스트하는 메서드

String 클래스 요구사항 2

(1,2) 값이 주어졌을 때 String의 substring() 메소드를 활용해 ()을 제거하고 1,2를 반환하도록 구현한다.

@Test
    @DisplayName("요구사항 2")
    void subString() {
        String str = "(1,2)";

        String subStringStr = str.substring(1,4);

        assertThat(subStringStr).isEqualTo("1,2");
    }

substring()

str.substring( start, end );

위와 같이 사용할 수 있으며, start와 end를 지정할 수 있다.
위 코드는 1과 4를 시작과 끝으로 지정해서 1,2가 나오는 것이다.

String 클래스 요구사항 3-1


"abc" 값이 주어졌을 때 String의 charAt() 메소드를 활용해 특정 위치의 문자를 가져오는 학습 테스트를 구현한다.

@Test
    @DisplayName("요구사항 3")
    void charAt() {
        String str = "abc";

        char c = str.charAt(2);

        assertThat(c).isEqualTo('c');
    }

charAt()

charAt()은 String으로 저장된 문자열 중에서 한 글자만 선택해서 char타입으로 변환해준다.

String 클래스 요구사항 3-2


String의 charAt() 메소드를 활용해 특정 위치의 문자를 가져올 때 위치 값을 벗어나면 StringIndexOutOfBoundsException이 발생하는 부분에 대한 학습 테스트를 구현한다.

@Test
    @DisplayName("요구사항 3 - 2 : assertThatThrownBy 를 사용한 Exception 처리")
    void StringIndexAtException() {
        String str = "abc";

        assertThatThrownBy(() -> {
            char c = str.charAt(5);
            assertThat(c).isEqualTo('c');
        }).isInstanceOf(StringIndexOutOfBoundsException.class)
                .hasMessageContaining("범위를 벗어난 오류");
    }

assertj의 Exception 별 제공되는 메서드

자주 발생하는 Exception의 경우 Exception별 메서드 제공하고 있음

  • assertThatIllegalArgumentException()
  • assertThatIllegalStateException()
  • assertThatIOException()
  • assertThatNullPointerException()

assertThatThrownBy()

자바 8 예외 assertion 표준 스타일이다.
예외를 처리하기 위한 방법 중 하나로 try~catch문으로 예외를 던졌을 때 테스트가 가능해진다.

  • hasMessage : 클래스에 있는 예외와 일치하는지 테스트를 진행함.

String 클래스 요구사항 3-3


@Test
    @DisplayName("요구사항 3 - 3 : assertThatExceptionOfType 을 사용한 Exception 처리")
    void StringIndexAtException2() {
        String str = "abc";

        assertThatExceptionOfType(StringIndexOutOfBoundsException.class)
                .isThrownBy(() -> {
                    char c = str.charAt(5);
                    assertThat(c).isEqualTo('c');
                }).withMessageContaining("범위를 벗어난 오류");
    }

assertThatExceptionOfType()

예외 클래스로 넘기는 방식으로 이 또한 assertThatThrownBy와 함께 예외를 처리하는 방법 중 하나이다.

Set Collection 요구사항 1


Set의 size() 메소드를 활용해 Set의 크기를 확인하는 학습테스트를 구현한다.

@Test
    @DisplayName("Set Size 구하기")
    void getSize() {
        int size = numbers.size();

        // Set은 중복을 허용하지 않음
        assertThat(size).isEqualTo(3);
    }

Set은 중복을 허용하지 않아서 1,1,2,3을 add해도 1,2,3만 add된다.

Set Collection 요구사항 2


Set의 contains() 메소드를 활용해 1, 2, 3의 값이 존재하는지를 확인하는 학습테스트를 구현하려한다.

JUnit의 ParameterizedTest를 활용해 중복 코드를 제거해 본다.

@ParameterizedTest
    @DisplayName("요구사항 2 : Set 내부 값의 존재 여부 확인")
    @ValueSource(ints = {1,2,3})
    void useValueSource(int nums) {
        assertTrue(numbers.contains(nums));
    }

@ParameterizedTest

  • 중복 코드가 발생했을 때 사용할 수 있다.
  • @Test 대신에 @ParameterizedTest를 사용하면 되고, @ParameterizedTest를 사용하게 되면 @ValueSource를 통해 최소 하나의 값을 넣어주어야 한다.

assertTrue

assertTrue, assertFalse 메서드는 boolean 값을 반환하는 메서드를 테스트하기에 적합하다.

Set Collection 요구사항 3


요구사항 2는 contains 메소드 결과 값이 true인 경우만 테스트 가능하다.

입력 값에 따라 결과 값이 다른 경우에 대한 테스트도 가능하도록 구현한다.

예를 들어 1, 2, 3 값은 contains 메소드 실행결과 true, 4, 5 값을 넣으면 false 가 반환되는 테스트를 하나의 Test Case로 구현한다.

@ParameterizedTest
    @DisplayName("요구사항 3 : CsvSource 사용하여 boolean 반환")
    @CsvSource(value = {"1:true","2:true","3:true","4:false","5:false"},delimiter = ':')
    void useCsvSource(int element, boolean expected) {
        assertThat(numbers.contains(element)).isEqualTo(expected);

        assertEquals(numbers.contains(element), expected);
    }

@CsvSource

  • 입력값에 따라 결과값이 다른 경우를 테스트 하려면 @CsvSource를 사용해 테스트를 할 수 있다.
  • 콤마(default)를 기준으로 CSV를 구분해서 읽는다.
  • @CsvSource 어노테이션에 delimiter 을 직접 정의함으로써 구분자를 지정할 수 있다.
profile
장래희망 : 침대 위 녹아든 치즈

0개의 댓글