if(kakao) 2020 의 강연을 듣고 정리해 보았습니다.

TDD 묻고 BDD로 가!

BDD(Behavior Driven Development)와 TDD(Test Driven Development)를 비교하고 BDD와 TDD를 통해 얻는 장점을 이야기해봅니다. 그리고, 예제를 통해 BDD를 적용하는 법을 살펴보고 BDD와 TDD를 kotlin project에서 쉽게 적용할 수 있도록 도와주는 kotest와 주변 라이브러리를 소개합니다.

TDD와 BDD

TDD란 테스트 주도 개발로 테스트를 미리 작성하고 해당 테스트가 작성할때까지 개발을 진행하는 것. 테스트를 돌려가면서 실패한 코드들을 수정하고 모든 테스트를 통과할 때 까지 개발을 진행하는 것. 그러나 일반적으로 테스트 케이스를 만든다는 것은 만들어진 코드의 검증을 위한 것이다. 그래서 테스트 케이스를 작성하는 모든 경우를 TDD라고 하지는 않는다. 테스트 케이스 작성 관점을 기준으로 구분을 해본다면 요구사항을 검증하기 위해 테스트 케이스를 작성하고 해당 테스트 케이스에 맞추어 코드를 개발하는 것과 코드를 먼저 작성한 후 해당 코드가 정상동작하는 지 검증하기 위해 테스트 케이스를 작성하는 것 두가지로 구분된다. 이 두가지가 모두 TDD라고 보기는 어렵고 전자의 경우를 TDD라고 부른다.

테스트 케이스를 먼저 작성하고 설계를 하게 되면 코드 설계가 테스트가능하게 된다는 장점이 있다. 요구사항의 변경시에도 테스트 케이스가 먼저 작성되기 때문에 tesable, 즉 “테스트가 가능한” 설계로 짜여진 코드 작성이 된다. testable하기 위해서는 테스트모듈이 명확해야 하는데 이러기 위해서는 모듈의 역할을 단순화하는 작업이 필요하다. 따라서 testable한 코드의 설계는 모듈의 크기를 줄이는 것을 유도하고 모듈 또는 계층간의 커플링도 적게 만들어 유지보수와 확장이 가능하게 하는 장점이 있다. 이는 TDD의 대표적인 장점이라 할 수 있다.

왜 TDD를 안할까?

이 장점을 개발자들이 잘 이해하고 있지만 TDD가 잘 이루어지지 않고 있다. 왜 TestCase 작성을 안할까? 아무래도 지속적인 테스트 케이스들의 유지 보수가 필요하게 되는데 개발 일정관리나 리소스 관리 측면에서의 부담이 크기 때문이다. 물론 귀차니즘도 한몫 한다고 한다 대부분의 개발자들의 테스트의 중요성을 알고 있고 TDD도입에 따른 장점에 공감하지만 비용에 대한 부담떄문에 도입하기 쉽지 않은 것이 현실이다. 테스트 케이스 작성을 위한 시간 할애, 개발 일정에 대한 압박, 촉박한 일정으로 인해 test없는 위험한 배포 들은 기술부채가 늘어나는 악순환의 이유가 되기 때문에 이것을 끊기 위해서라도 테스트 케이스 작성에 들어가는 비용을 받아들여야 한다. 한마디로 필요성 < 비용이 되는 상황. 하지만 테스트 케이스를 상상해서 만드는 것이 아니라 요구사항이나 기획서가 바로 테스트 케이스가 된다면 테스트 케이스 작성에 대한 고민은 줄고 비용 감소의 효과가 있을 수 있다. 그럼 어떻게 요구사항이 바로 테스트 케이스가 되는가? 오늘 이야기할 주제가 바로 이것을 가능하게 해주는 BDD!(Behavior Driven Development)

BDD란?

  • TDD에서 파생된 개발 방법론
  • 개발자와 비개발자간의 협업 과정을 녹여낸 방법
  • 사용자의 행위를 작성하고 결과 검증을 진행
  • BDD로 테스트 코드를 작성함에 따라 설계 역시 행위의중심이 되는 도메인 기반 설계가 된다.

BDD란 사용자의 행위를 정의하고 정의한 행동에 따라 개발해 나가는 것이라 볼 수 있다. 테스트케이스를 ‘이미 정의된 사용자의 행위’로 하면 되는데 이 행위들은 친절하게도 기획자가 작성한 요구사항이나 기획서에 적혀 있는데 이것을 개발자가 코드로 읽으면 된다. BDD를 위해 이미 연구되고 어느정도 정의된 몇가지 형식이 있으니 함께 보자.

유저 스토리를 통해 작성된 기획서에 있는 요구사항 하나 하나씩을 시나리오로 작성한다. 이 시나리오의 구조는 Given(주어진 환경), When(행위), Then(기대결과) 세 가지로 이루어진다. Given 은 사용자 행위 시 주어진 환경을 서술하고 When 은 실제 사용자의 행위를 서술한다. 그리고 Then 은 그 행위에 따른 결과를 서술한다.

이모티콘 스튜디오에 검수 기능을 추가하는 기획서 라는 간단한 예시를 통해 더 자세히 알아보자.

- 검수 등록 필수 조건: 서비스 가입 여부 ,로그인 여부, 본인 인증 여부
- 검수 등록 입력사항: 이모티콘 정보, 이모티콘 이미지
- 등록시
	* 정상 등록 된 경우: 검수 진행 목록으로 이동하여 등록된 내용이 표시되어야 함
	* 등록 실패된 경우: 등록 실패 사유가 표시되어야 함

이것을 Given, When, Then으로 구조화한다면

- Given
"본인 인증된 사용자가 로그인된 상황에서"
- When
"검수 정보를 입력하고 검수 등록 버튼을 누르면"
"검수 정보를 미입력하고 검수 등록 버튼을 누르면"
- Then
"등록 결과가 포함된 검수 진행 목록 화면으로 이동한다"
"검수 등록 실패 사유가 화면에 표시되어야 한다"

이 G-W-T만 보더라도 쉽게 해야할 일을 알 수 있다. BDD로 작성된 테스트코드를 보면 그 자체로 기획서와 동기화가 된다. 그래서 기획서의 내용이 모두 BDD 테스트 케이스로 작성이 된다면 빈 틈 없는 서비스 설계가 가능해진다. 이를 통해 테스트 케이스 작성에 대한 고민을 줄일 수 있다. 이를 위해 기획서를 꼼꼼히 읽어보고 서비스에 대한 이해 역시 높일 수 있다. 그렇다면 굳이 TDD와 BDD를 나누는 이유는 무엇일까?

TDD와 BDD의 차이

TDD와 BDD는 테스트 케이스 관점 상의 차이가 있었던 것 처럼 구분지을 수 있는 차이가 있다. 바로 테스트 케이스의 목적에서 차이가 있는데 TDD의 테스트 케이스는 테스트할 모듈의 기능을 확인하는 것이 관점이 되고 BDD의 테스트 케이스는 시나리오 주체를 기준으로 한 행위를 확인하기 위한 관점에서 작성이 된다.

BDD%E1%84%8B%E1%85%AA%20TDD%201e501e0588104c218c69b211f9341062/Screen_Shot_2020-11-25_at_2.28.25_PM.png

BDD의 테스트 케이스는 TDD 테스트 케이스의 묶음이라고 볼 수 있다. BDD는 TDD에서 파생된 개념으로 유저 시나리오의 흐름을 확인할 수 있다. 하지만 BDD의 테스트 케이스 만으로는 완벽하지 않고 BDD의 테스트 케이스로 시나리오 검증을 한 뒤 해당 시나리오에서 사용되는 각 모듈들은 TDD의 테스트 케이스로 검증을 해야 기대하는 테스트 커버리지를 가질 수 있다.

BDD%E1%84%8B%E1%85%AA%20TDD%201e501e0588104c218c69b211f9341062/Screen_Shot_2020-11-25_at_2.35.26_PM.png

따라서 BDD와 TDD는 서로 다른 것이 아닌 상호보완적인 개념이라고 볼 수 있다. 따라서 동작 사이클을 그려본다면 BDD의 사이클에 여러 개의 TDD 사이클이 붙어있는 구조로 그려지게 된다.

기획이 변경되거나 오류 케이스를 추가적으로 발견 시 해당 상황에 따라 설계를 다시 해야하여 기존 코드 수정이 커지는 리스크가 있었다. 이 때 누락된 기획을 추가하면서 설계 자체가 변경되어 코드 작성이 대대적으로 바뀌어야 하는 리스크가 생길 수 있다. 문제는 이런 경우가 배포까지 이루어진 상황에서도 종종 발생한다는 것이다. 이러한 리스크를 미연에 방지하기 위해서는 기획의 검토가 충분히 이루어져야 하는데 BDD에서는 입력값의 예외 케이스를 찾아서 추가하듯이 기획 시나리오의 빈틈들을 테스트 케이스 작성 시에 확인할 수 있는 장점이 있다. BDD를 통해 시나리오의 빈틈을 코드 작성 전에 발견할 수 있기 때문에 큰 변경을 해야하는 상황을 회피할 수 있다. 테스트 케이스에 서술된 스크립트로 발견하기 더 쉽다.

- Given
"본인 인증된 사용자가 로그인된 상황에서"
if "본인 인증 안된 사용자가 로그인한 상황에서"
if "본인 인증이 어려운 미성년 사용자가 로그인된 상황에서"
- When
"검수 정보를 입력하고 검수 등록 버튼을 누르면"
"검수 정보를 미입력하고 검수 등록 버튼을 누르면"
- Then
"등록 결과가 포함된 검수 진행 목록 화면으로 이동한다"
"검수 등록 실패 사유가 화면에 표시되어야 한다"

이러한 시나리오의 빈틈은 기획 단계에서 빠진 부분들을 일정 연기 없이 추가하려다가 누더기 코드를 만들게 되는 원인이 된다. 실제 설계가 이루어지기 전에 BDD 테스트 케이스 작성을 통해 시나리오 검증과 그로 인한 리스크 감소라는 결과를 얻을 수 있다. 또한 더 충실한 시나리오를 만들 수 있고 더 튼튼한 설계가 가능해진다.

BDD%E1%84%8B%E1%85%AA%20TDD%201e501e0588104c218c69b211f9341062/Screen_Shot_2020-11-25_at_2.45.02_PM.png