소프트웨어 공학

[Go with TDD] TDD란?

소프트웨어 공학, 개발 방법론 등에 관해 조금이라도 알고 있다면 TDD(Test-driven development, 테스트 주도 개발)라는 용어를 들어봤을 것이다. 잘 아는 사람도 많겠지만 모르는 사람들을 위해서 우선 용어부터 정리해보자.

TDD

단어 그대로 테스트를 통해서 개발하는 방식이다. 즉, 테스트 케이스를 작성한 후 그 테스트를 통과하기 위한 코드를 짜는 방식을 TDD라고 부른다.

회귀 테스트

회귀 테스트는 이전에 동작 했던 기능 및 함수가 다른 부분의 코드 수정 후에도 일관성 있게 동작하는 것을 검증하는 테스트이다. 회귀 테스트는 일단 작성되면 새로운 기능을 테스트할 때마다 실행된다. 회귀 테스트의 핵심은 기존의 코드가 새로운 기능에 의해 문제를 일으키지 않는다는 것을 검증하고 보증하는 것에 있다.

단위 테스트

단위 테스트는 프로그램을 기능 단위로 쪼개서 각각의 기능을 검증하는 테스트이다. 회귀 테스트의 특징을 가지고 있으며 TDD에서 사용하는 테스트의 기본 단위이다.

TDD의 효과

그렇다면 왜 이런 수고스러운 절차를 거쳐야 할까? 방법론이 으레 그렇듯 그런 방법론을 적용하는 이유와 적용할 때 주의할 점을 인지하고 있어야 잘 활용할 수 있다.

장점

개발 과정에 테스트를 내포하기 때문에 코드 작성 단계에서 버그를 어느정도 줄일 수 있다. 또한 TDD에 사용할 단위 테스트를 실행하기 위해 기능을 아주 작은 단위의 함수로 쪼개게 되고, 이는 코드 작성과 리팩토링이 동시에 이루어지게끔 만든다. 마지막으로 한 번 통과된 단위 테스트는 기능이 추가될 때마다 실행되어 기존의 기능이 새로운 기능에 영향을 받지 않게 만들어 여러 함수들이 얽힌 복잡한 버그를 방지할 수 있다.

즉, 함수를 작성할 때마다 디버깅과 리팩토링, 회귀 테스트를 동시에 진행하는 효과를 지닌다.

단점

멀티 쓰레드(golang의 경우 고루틴)를 사용하는 함수와 같이 단위 테스트를 작성하기 어려운 기능은 TDD를 적용하기가 어렵다. 또한 유닛 테스트에 묶여 더 좋은 설계가 있음에도 테스트가 불가능하거나 어려워서 선택하지 못하는 아이러니한 상황 -TDD를 위한 TDD라는 재밌는 표현이 있다- 에 놓일 수도 있다. 기존 코드 작성 시간에 비해 오래 걸린 것을 단점으로 들 수도 있는데, 이는 위의 장점에서 언급한 여러 절차가 묶여져 있다는 것은 유의해야 한다.

TDD의 주기

TDD는 크게 4개의 단계로 이루어져 있다.

1. 함수 정의

먼저 함수를 정의해야 한다. 이 단계에서는 함수의 인자와 결과, 즉 입력과 출력을 명확히 해야 한다. 단, 함수 내부의 코드는 구현하지 않는다. 이유는 테스트 실행 단계에서 설명하겠다.

2. 테스트 작성

테스트 파일과 테스트 케이스를 테스트 프레임워크에 맞춰 작성해야 한다. 테스트 케이스로는 일반적인 입력 및 출력, 특수한 처리가 필요한 입력 및 출력, 오류를 일으킬 수 있는 입력 및 출력을 고려해야 한다. 오류를 일으키는 흔한 경우로는 오버플로우, 배열 인덱스, 0으로 나누기가 있다.

3. 테스트 실행

테스트를 실행한다. 테스트가 성공할 경우 1번으로 가서 새로운 함수를 정의한다.

처음 실행할 경우에는 함수 정의가 되어있지 않기 때문에 반드시 실패가 떠야 한다. 앞서 함수 정의 단계에서 함수를 구현하지 않은 것도 테스트의 실패 판정 여부를 확인하기 위함이었다. 실패가 뜨지 않는다면 테스트 케이스에서 판정 부분이 있는지 확인해 봐야 한다. 판정 없는 테스트는 테스트가 아니다.

4. 함수 수정

함수 내의 코드를 작성 및 수정한다. 이 과정을 완료하면 3번으로 돌아가 테스트를 실행한다. 또, 이 과정에서 특수하거나 오류를 일으킬 법한 케이스를 발견하면 2번으로 돌아가 그에 관한 테스트 케이스를 추가한다.

마치며...

이번 글에서는 TDD란 무엇이며 TDD 장점과 단점, TDD의 절차에 대해 알아봤다. 다음 글에서는 Go언어의 내장 테스트 프레임워크인 go test와 이를 이용한 TDD 적용법에 대해 간단한 예시를 들며 설명하겠다.

참고 자료