CHAP 04. TDD/기능 명세/설계

테스트 주도 개발 시작하기 4장을 요약한 내용입니다.

기능 명세

사용자가에게 제공할 기능을 구현하려면 기능을 크게 두 가지로 나누어 생각해 볼 수 있다. 그것은 입력과 결과이다. 예를 들어 로그인 기능을 생각해보자.

  • 입력 : 아이디와 암호

  • 결과 : 아이디와 암호가 일치하면 성공, 일치하지 않으면 실패

3장에서 살펴본 만료일 계산 기능의 입력과 결과는 다음과 같다.

  • 입력 : 첫 납부일, 납부일, 납부액

  • 결과 : 만료일

결과는 여러 형식으로 정의할 수 있다.

  • 리턴 값

  • 익셉션

결과는 상황에 따라 달라질 수 있다.

  • 회원 가입 시 동일 ID 존재 → DuplicationException 발생

  • 회원 가입 시 동일 ID 없음 → 회원 정보 DB에 저장 후 회원 일련 번호 리턴

설계는 기능 명세로부터 시작한다.

기능 명세를 구체화하는 동안 입력과 결과를 도출하고 이렇게 도출한 기능 명세를 코드에 반영한다. 기능 명세의 입력과 결과를 코드에 반영하는 과정에서 기능의 이름, 파라미터, 리턴 타입 등이 결정된다. 이는 곧 기능에 대한 설계 과정과 연결된다.

설계 과정을 지원하는 TDD

TDD는 테스트 코드를 먼저 만들고 테스트를 통과시키기 위해 코드를 구현하고 리팩토링하는 과정을 반복한다.

테스트 코드를 먼저 만들기 위해 무엇이 필요할까?

  • 테스트할 기능을 실행

  • 실행 결과를 검증

기능을 실행할 수 없으면 테스트를 할 수 없다.

  • 테스트에서 실행할 수 있는 객체나 함수가 존재해야 한다.

  • 실행할 객체가 존재하려면 클래스가 필요하고 메서드도 필요하다

  • 클래스나 메서드를 정의하기 위해서는 이름을 결정해야 한다.

  • 메서드를 실행할 때 사용할 인자의 타입과 개수를 결정해야 한다.

이전 예제에서 테스트 코드를 작성하는 과정에서 다음의 네 가지를 결정했다.

  • 클래스 이름

  • 메서드 이름

  • 메서드 파라미터

  • 실행 결과

필요한 만큼 설계하기

TDD는 테스트를 통과할 만큼만 코드를 작성한다. 필요한 것으로 예측해서 미리 코드를 만들지 않는다. 이는 설계에도 동일하게 적용된다. 필요한 것으로 예측해서 미리 설계를 유연하게 만들지 않는다. 실제 테스트 사례를 추가하고 통과시키는 과정에서 필요한 만큼 설계를 변경한다.

기능 실행 결과도 동일하다

미리 앞서서 필요해 보이는 익셉션 타입을 만들지 않는다. 테스트를 진행하는 과정에서 실제 익셉션이 필요한 시점에 익셉션을 도출한다. 예를 들어 중복된 ID가 존재하는 경우 회원 가입에 실패하는 테스트를 추가하는 시점에 비로소 DuplicationException 타입을 추가한다.

TDD로 개발할 때 필요한 만큼 설계를 한다고 해서 사전에 설계 활동을 생략하는 것은 아니다. 요구사항을 분석하는 과정에서 당연히 설계를 진행한다. 단 이때 설계한 결과물은 초안에 불과하다. 이 초안대로 처음부터 끝까지 개발된다는 보장은 없다. TDD는 미리 앞서서 코드를 만들지 않으므로 불필요한 구성 요소를 덜 만들게 된다.

기능 명세 구체화

테스트 코드를 작성하기 위해 개발자는 기능 명세를 정리해야 한다. 테스트 코드를 작성하려면 파라미터와 결과 값을 정해야 하므로 개발자는 요구사항 문서에서 기능의 입력과 결과를 도출해야 한다. 또한, 다양한 테스트 사례를 추가하는 과정에서 구현하기 애매한 점을 발견하게 된다. 테스트 코드는 구체적인 입력과 결과를 이용해서 작성하므로 개발자는 예를 통해 기능 명세를 구체화하게 된다.

만료일 계산 기능을 예로 들어보자

  • 서비스를 사용하려면 매달 1만 원을 선불로 납부한다. 납부일 기준으로 한 달 뒤가 서비스 만료일이 된다.

  • 2개월 이상 요금을 납부할 수 있다.

  • 10만 원을 납부하면 서비스를 1년 제공한다.

테스트를 작성하려면 개발자는 한 달 뒤에 대한 정확한 예가 필요하다. 이를 위해 개발자는 다음과 유사한 대화를 통해 구체적인 예를 찾게 된다.

  • 개발자 : 만 원을 납부하면 서비스 만료일이 납부한 날로부터 한 달 뒤잖아요?

  • 기획자 : 네 그렇죠. 만 원을 내면 한 달 뒤가 만료일이 됩니다.

  • 개발자 : 4월 1일에 만원을 납부하면 만료일은 언제예요? 4월 30일인가요? 5월 1일인가요?

  • 기획자 : 5월 1일이예요

  • 개발자 : 혹시 1월 31일에 만원을 납부하면 만료일은 언제인가? 2월 28일인가요? 아니면 30일 뒤인 3월 2일인가요?

  • 기획자 : 그 경우네는 2월 28일이 만료일이예요

  • 개발자 : 만약 윤년인 경우는 어떻게 되나요?

  • 기획자 : 윤년이면 2월 29일이 만료일이 됩ㄴ다.

  • 개발자 : 질문 하나 더요. 1월 29일이나 1월 30일에 만원을 납부해도 2월 28일인가요? 윤년이면 2월 29일이 되구요?

  • 기획자 : 네 맞아요

  • 개발자 : 그러면 1월 31일이나 5월 31일처럼 만원을 납부한 일자가 다음 달 말일 일자보다크면 이때 만료일은 다음 달 말일이라고 생각하면 될까요?

  • 기획자 : 네!

개발자에게 기능 명세는 필수다

구체적인 예를 이용해서 테스트 코드를 추가하다 보면 기능 명세를 보다 잘 이해하고 모호함을 없앨 수 있다. 이러한 테스트 코드 작성은 유지보수에 큰 도움이 된다. 특정 상황에서 코드가 어떻게 동작하는지 이해하고 싶다면 해당 상황을 검증하는 테스트를 실행하고 이해가 필요한 코드를 추적하면 된다. 복잡한 로직을 구현해야 하는 것은 결국 개발자이므로 개발자는 최대한 예외적인 상황이나 복잡한 상황에 해당하는 구체적인 예를 끄집어내야 한다.

Last updated