본문 바로가기

TIL

[SpringMVC][TDD]

728x90

학습 목표

  • TDD가 무엇인지 이해할 수 있다.

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

테스트가 개발을 주도하는 방식, TDD는 테스트 코드를 먼저 작성하고 그 다음에 기능을 구현한다.

 

  • TDD의 개발 흐름을 이해할 수 있다.

TDD는 모든 조건에 만족하는 테스트를 먼저 진행한 뒤에 조건에 만족하지 않는 테스트를 단계적으로 진행하면서 실패하는 테스트를 점진적으로 성공시켜 나간다
TDD는 테스트 실행 결과가 "failed"인 테스트 케이스를 지속적으로 그리고 단계적으로 수정하면서 테스트 케이스 실행 결과가 "passed"가 되도록 만든다
TDD는 테스트가 "passed"될만큼의 코드만 우선 작성한다

TDD는 "실패하는 테스트 -> 실패하는 테스트를 성공할 만큼의 기능 구현 -> 성공하는 테스트  -> 리팩토링 -> 실패하는 테스트와 성공하는 테스트 확인 "이라는 흐름을 반복한다.

 

TDD가 아닌 전통적인 개발 방식

우리가 어떤 서비스 애플리케이션을 개발할 때 개발 절차는 일반적으로 다음과 같다. (고객의 요청으로 고객이 원하는 시스템을 구축하는 것이 아니라 서비스 제공 기업에서 불특정 다수의 회원에게 제공하는 서비스 애플리케이션을 의미한다)

  1. 서비스 제작에 관여하는 이해 당사자(기획자,프런트엔드,백엔드,웹디자이너 등)가 모여 서비스에 대한 컨셉과 해당 컨셉에 따른 요구사항을 지속적으로 수집한다
  2. 수집된 요구사항에 맞춰 서비스를 화면으로 제공하기 위한 UI를 설계하면서 구체적인 기능 요구 사항들을 정의한다
  3. 프런트앤드 개발자는 기능 요구 사항과 UI를 통해 프런트엔드 측 개발을 진행하고, 웹 디자이너는 화면을 디자인 하며, 백엔드 개발자는 기능 요구 사항에 맞춰 백엔드 애플리케이션을 디자인한다

앞에서 얘기한 개발 절차는 일반적인 흐름이긴 하지만 애자일 방식으로 1주~3주 단위로 기획, 설계, 구현을 반복적으로 빠르게 진행하면서 애플리케이션을 완성하는 방식을 도입한느 기업도 많이 있다.

3번 과정에서 백엔드 개발자의 개발 흐름은

  1. 이해 당사자들 간에 수집된 요구 사항과 설계된 화면(UI 설계서 등)등을 기반으로 도메인 모델을 도출한다
  2. 도출된 도메인 모델을 통해 클라이언트의 요청ㅇ르 받아 들이는 엔드포인트와 비즈니스 로직, 데이터 액세스를 위한 클래스와 인터페이스 등을 설계해서 큰 그림을 그려본다
  3. 클래스 설계를 통해 애플리케이션에 대한 큰 그림을 그렸으면 크랠스와 인터페이스의 큰 틀을 작성한다
  4. 클래스와 인터페이스의 큰 틀을 작성 되었다면 클래스와 인터페이스 내에 메서드를 정의하면서 세부 동작을 고민하고 코드로 구현한다.
  5. 해당 메서드의 기능 구현이 끝났다면 구현한 기능이 잘 동작하는지 테스트한다
  6. 테스트에 문제가 생기면 구현한 코드를 디버깅하면서 문제의 원인을 찾는다.

백엔드 개발 흐름 중, TDD 관점에서 두드러지는 점 한가지는 3~6번의 과정에서 구현이 먼저고 테스트가 나중이라는 점이다.

TDD방식으로 개발하며 TDD의 특성 알아보기

회원 등록시, 입력하는 로그인 인증용 패스워드의 유효성을 검증하는 기능을 TDD 방식으로 개발한다고 가정하면,

먼저 간단히 구현 할 패스워드 유효성 검증에 통과하는 조건은

  • 패스워드 길이는 8~20 사이의 길이여야한다
  • 패스워드는 알파벳 소문자 + 앞라벳 대문자 + 숫자 + 특수문자 형태로 구성되어야한다
  • 알파벳 대/소문자와 숫자를 제외한 모든 문자는 특수문자라고 가정한다
public class PasswordValidatorTest {
    @DisplayName("패스워드 유효성 검증 테스트: 모든 조건에 만족")
    @Test
    public void validatePassword() {
        
    }
}

 구체적인 테스트 코드가 없기 때문에 실행결과는 passed이다

모든 유효성 검증 조건을 만족하는 테스트

테스트 케이스의 컴파일 에러 수정 완료

PasswordValidator 클래스 를 생성후 validate() 메서드를 생성해서 에러를 해결 

 "failed"인 테스트 케이스를 지속적으로 그리고 단계적으로 수정하면서 테스트 케이스의 실행 결과가 "passed"가 되도록 만들고 있다.

TDD에서는 테스트가 passed 될 만큼의 코드만 우선 작성한다.

 

알파벳 대/소문자 + 숫자 + 특수문자 조건에서 특수문자가 빠진 경우 테스트

특수문자가 빠진 경우 테스트

 특수문자가 빠졌을 경우 에러가 발생하게 만들기 위해서는 처음 앞과 같이 똑같은 메서드를 만든다

PasswordValidator의 validate()에 Exception을 던지도록 수정

 passwordValidator에 throw new RuntimeException을 이용해서 테스트케이스의 테스트가 failed나오게끔 변경

특수문자를 포함하고 있는지의 여부를 체크한 뒤에 특수문자를 포함하고 있지 않을 경우에만 예외를 던지도록 기능을 수정

PasswordValidator 클래스 리팩토링
모든 테스트 케이스는 통과햇는데, 다른 조건을 만족하는 로직이 추가되면 passwordValidator 클래스의 유효성 검증 로직 코드가 깔끔하지 않을것같아 정규 표현식을 사용하여 패스워드의 유효성 검사를 진행하도록 리팩토링 하자.

특수문자가 포함 여부를 정규 표현식으로 검증하도록 수정

수정 후 테스트를 실행해보면 특수문자가 있는 test의 경우 pass가 되고, 특수문자가 없는 경우 failed가 발생된다
기능이 잘 작동되면 validatePasswordWithoutSpecialCharacter()메서드 삭제

 즉 TDD를 단계적으로 진행하는 방법은

  • 패스워드가 특수문자를 포함하면서 알파벳 소문자를 포함하는지 테스트, 검증, 리팩토링 단계 반복
  • 패스워드가 특수문자 + 알파벳 대/소문자를 포함하는지 테스트, 검증, 리팩토링 단계 반복
  • 패스워드가 특수문자 + 알파벳 대/소문자 + 숫자를 포함하는지 테스트, 검증, 리팩토링 단계 반복
  • 패스워드가 특수문자 + 알파벳 대/소문자 + 숫자를 포함하면서 8~20 길이를 만족하는지 테스트, 검증, 리팩토링 단계 반복

TDD의 특징 정리

장점

  • 테스트를 통과 할 만큼의 기능을 구현하므로 한번에 너무 많은 기능을 구현할 필요가 없다
  • 테스트의 코드가 추가되면서 검증하는 범위가 넓어질 수록 기능 구현도 점진적으로 완성되어간다
    즉, 단순한 기능에서 복잡한 기능으로 확장 되면서 그때 그때 검증을 빼먹지 않고 할 수 있다
  • 리펙토링 할 부분이 눈에 보이면 그때 그때 리팩토링을 빠르게 진행하기 때문에 리팩토링의 비용이 상대적으로 적어진다
    실무에서 하나의 기능을 완성해놓고 보면 리팩토링이 필요한 부분이 눈에 들어오는 경우가 많은데 일정상의 이유로 리팩토링을 하지 않고, 대충 넘어가는 경우가 많은데 TDD에 익숙해지면 그때 그때 리팩토링을 진행하게 되므로 리팩토링에 대한 비용이 상대적으로 적어질 가능성이 높다
  • 이미 잘 작동하는 코드를 수정하는 일은 부담스럽지만 TDD방식에서는 항상 테스트 케이스가 존재하기 때문에 기존 코드를 수정하더라도 상대적으로 심리적 불안감이 줄어들 수 있다.
  • 리팩토링을 통해 꾸준히 코드를 개선하므로 코드의 품질을 일정 부분 유지할 수 있다
    리팩토링이 전혀 이루어지지 않은 상태에서 코드 품질이 점점 나빠져가는 상태로 애플리케이션이 구현되고있는 모습을 상상해보면 그만큼의 유지보수 비용이 높아진다는 사실을 알수있을것이다.
  • 코드 수정이후 바로 테스트를 진행할 수 있으므로 코드 수정 결과를 빠르게 피드백 받을수 있다.

단점

  • TDD의 개발 방식이 익숙하지 않다
  • 테스트 코드의 작성에 익숙하지 않은 사람, 테스트 코드를 작성하길 원치 않는 사람들에게는 부정적인 방식일수있다
    기능 구현이 끝나더라도 테스트 없이 하나의 애플리케이션이 릴리즈 되지 않는다. 
  • 팀단위로 개발을 진행해야하므로 팀원들 간 사전에 협의가 되어야한다
    TDD방식을 적용하기 위해서는 팀 차원에서 TDD방식에 대한 논의가 필요하고 팀원들 각자가 TDD를 수용하고, 적용해보려는 합의가 필요하다
728x90

'TIL' 카테고리의 다른 글

[Spring MVC][Spring Rest Docs]  (0) 2022.11.11
[Spring MVC][API 문서화]  (0) 2022.11.11
[Spring MVC][Mockito]  (0) 2022.11.10
[Spring MVC][Slice Test]  (0) 2022.11.09
[JUnit으로 비즈니스 로직에 단위 테스트 적용하기]  (0) 2022.11.09