TDD(Test Driven Development), 테스트 주도 개발

hzbbo·2022년 12월 5일
0

Theory

목록 보기
1/2
post-thumbnail

TDD 란?

반복 테스트를 이용한 소프트웨어 방법론으로,
작은 단위의 테스트 케이스를 작성하고 이를 통과하는 코드를 추가하는 단계를 반복하여 구현한다.

단위 테스트(Unit Test) 란?
하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트
(여기서 모듈은 애플리케이션에서 작동하는 하나의 기능 또는 메소드)

TDD 개발 주기


RED : 실패하는 단위 테스트 코드를 작성
Green : 테스트 코드를 성공시키는 실제 코드 작성
Blue : 중복 코드 제거, 일반화 등의 리팩토링 수행

이 과정을 계속 반복하여 개발을 진행한다.

TDD 간단한 예제로 구현

IntelliJ, JDK 1.8, Gradle

프로젝트가 성공적으로 생성되었다면 네모 박스 안에 보이는 JUnit5 의존성이 주입된 것을 확인할 수 있다.

JUnit5 : Java 단위 테스팅 프레임워크
https://junit.org/junit5/docs/current/user-guide/#writing-tests
https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/

AssertJ : 테스트 코드 가독성을 높여주는 자바 라이브러리
https://assertj.github.io/doc/#assertj-core-assertions-guide

테스트 코드를 작성하기 전 요구사항을 먼저 만들어보자!

요구사항

  • 비밀번호는 최소 6자 이상 12자 이하여야 한다.
  • 비밀번호가 6자 미만 또는 12자 초과인 경우 IllegalArgumentException 예외를 발생시킨다.
  • 경계조건에 대해 테스트 코드를 작성해야 한다.

src > test 에서 PasswordValidatorTest 생성해주고 요구사항 하나씩 테스트 진행

public class PasswordValidatorTest {

	/* PasswordValidator 클래스에 있는 validate 메소드에 password 라는 인자를 주고 Test 진행 */
   
    @DisplayName("비밀번호는 최소 6자 이상 12자 이하면 예외가 발생하지 않는다.")
    @Test
    void validatePasswordTest() {
        assertThatCode(() -> PasswordValidator.validate("password123"))
                .doesNotThrowAnyException();
    }
}

assertThatCode() : 예외를 던지지 않는 경우 처리
doesNotThrowAnyException : 에러가 발생하지 않는다면 Test 통과

테스트 코드를 작성하고 이 코드를 성공시킬 실제 코드를 src > main 에서 PasswordValidator 클래스 생성

public class PasswordValidator {

    public static void validate(String password) {
    
        if(password.length() < 6 || password.length() > 12) {
            throw new IllegalArgumentException("비밀번호는 최소 6자 이상 12자 이하여야 한다.");
        }
    }
}

이제 테스트 코드를 실행시키면,

다음과 같이 성공적으로 테스트가 진행된 걸 확인할 수 있다.

이제 실제 코드의 리팩토링을 진행

public class PasswordValidator {

    public static void validate(String password) {
    
        if(password.length() < 6 || password.length() > 12) { // password.length() 중복
            throw new IllegalArgumentException("비밀번호는 최소 6자 이상 12자 이하여야 한다."); // Exception Message 일반화
        }
    }
}

password.length()와 Exception Message를 따로 선언해주는 식으로 리팩토링

public class PasswordValidator {
    public static final String WRONG_PASSWORD_LENGTH_EXCEPTION_MESSAGE = "비밀번호는 최소 6자 이상 12자 이하여야 한다.";
    public static void validate(String password) {
    
            int length = password.length();

            if (length < 6 || length > 12) {
                throw new IllegalArgumentException(WRONG_PASSWORD_LENGTH_EXCEPTION_MESSAGE); //
            }
        }
}

Refactor 단축키
Introduce Variable : ctrl+alt+v
Introduce Constant : ctrl+alt+c

나머지 Test Code 참고!

public class PasswordValidatorTest {

    @DisplayName("비밀번호는 최소 6자 이상 12자 이하면 예외가 발생하지 않는다.")
    @Test
    void validatePasswordTest() {
        assertThatCode(() -> PasswordValidator.validate("password123"))
                .doesNotThrowAnyException();
    }

    @DisplayName("비밀번호가 6자 미만 또는 12자 초과하는 경우 IllegalArgumentException 예외가 발생한다.")
    @Test
    void validatePasswordTest2() {
        assertThatCode(() -> PasswordValidator.validate("abcd"))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessage("비밀번호는 최소 6자 이상 12자 이하여야 한다.");
    }

    @DisplayName("비밀번호가 6자 미만 또는 12자 초과하는 경우 IllegalArgumentException 예외가 발생한다.")
    @ParameterizedTest
    @ValueSource(strings = {"abcde", "abcdeabcdefgh"})
    void validatePasswordTest3(String password) {
        assertThatCode(() -> PasswordValidator.validate(password))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessage("비밀번호는 최소 6자 이상 12자 이하여야 한다.");

    }
}

instanceOf : 객체가 어떤 클래스인지, 어떤 클래스를 상속받았는지 확인하는데 사용하는 연산자

  • IllegalArgumentException 클래스를 받는지 확인하는 용도로 쓰임
  • hasMessage() 해당 메시지를 가지는지 쓰임

@ParameterizedTest : 매개 변수가 있는 테스트 메서드를 식별
@ValueSource : 테스트 메서드에 매개 변수 주입

0개의 댓글