테스트 주도 설계 (TDD) (Beck 2003; Astels 2003)는 테스트 선행 개발과 개발을 하기 위한 혁신적 접근이다. TDD의 기본적인 목적은 무엇인가? 어떤 관점에서는 TDD의 목적이 사양에 있지, 검증은 아니라고 한다(Martin, Newkirk, and Kess 2003). 다른 말로, 기능적인 코드를 작성하기에 앞서, 설계를 통해 사고하기 위한 방법이라는 것이다. Ron Jeffries는 TDD의 목표는 코드를 깔끔하게 하는 역할을 한다고 한다. 비록 필자는 사양이라는 관점에 치우처 있긴 하지만 두 요소 모두에 장점이 있다고 생각하고, 그것은 독자가 결정해야 할 부분으로 남겨둔다.
목차
1. TDD란 무엇인가?
테스트 선행 설계 (TFD) 단계들은 그림1의 UML 액티비티 다이어그램에서 볼 수 있다. 첫 단계는 기본적으로 코드가 실패하지 않게끔만, 빨리 테스트를 추가하는 것이다. 다음은 테스트 스위트가 완성되어 있을지라도 빠른 속도를 위해서 단 하나의 하위 집합만 실행하여 테스트가 실패했다는 사실을 확인하도록 테스트를 돌려보는 것이다. 그리고 나서 새로운 테스트가 통과할 수 있도록 기능 코드를 수정한다. 네번째 단계는 테스트들을 다시 돌려보는 것이다. 이것이 실패 하면 기능 코드들을 수정하고 재테스트를 수행한다. 테스트들이 한번 통과하면 끝이다. (중복을 제거하는 리팩터링을 수행하기 위해서는 TFD에서 TDD로 바꾸어야 할 필요가 있다.)
그림1. 테스트 선행 개발 단계 (TFD).

나는 TDD를 다음과 같은 간단한 공식으로 묘사하고 싶다 :
TDD = Refactoring + TFD.
TDD는 전통적인 개발 방법을 완전히 바꾸어놓았다. 하나의 새로운 기능을 구현하려고 할 때, 가장 먼저 올 질문은 기능적으로 구현에 있어 기존의 설계가 가능한 최상의 설계인가 하는 것이다. 그렇다면 TFD 로 접근하기로 할 것이고, 그렇지 않다면, 새로운 기능에 의해 영향을 받은 부분을 가능한한 쉽게 추가함으로써 리팩터링 한다. 결과적으로 설계의 품질은 항상 향상될 것이고, 그렇기 때문에 앞으로는 작업하기 쉬워질 것이다.
기능 코드와 테스트코드를 모두 작성한다면, 기능 코드를 먼저 작성하고 테스팅 코드를 나중에 작성하는 대신에 기능코드를 작성하기 전에 테스트 코드를 작성하라. 하나의 테스트와 기능코드에 대응하는 작은 비트라는 아주 적은 단계로 할 수 있다. 프로그래머는 TDD 접근을 함으로써, 기능이 주어지지 않았기 때문에 첫번째 테스트가 실패 할 때까지 새로운 기능을 작성하지 않게 된다. 사실, 그러한 테스트가 있는 동안에는 단 한 줄의 코드도 추가하지 않을 것이다. 테스트 스위트가 모두 통과함을 확인하는 것으로 업무를 수행했다는 것을 보장한다 (새로운 코드는 기존의 테스트들을 망가뜨릴 수도 있다). 이는 간단한 원칙이지만 TDD 접근 증명을 처음으로 배우기 원한다면 커다란 규율이 필요하다. 왜냐하면 미끄러지거나 새로운 테스트를 먼저 작성하지 않으면서 기능 코드를 작성하기 십상이기 때문이다. 짝 프로그래밍이 완주 할 수 있도록 도와줄 것이다.
TDD는 단위 테스팅 프레임웍을 사용할 수 있음을 전제한다. 대부분의 애자일 소프트웨어 개발자는 JUnit 또는 VBUnit 같은 오픈소스 툴 같은 xUnit 계열을 사용하지만 상업용 도구나 다른 것들도 괜찮다. 이러한 도구가 없이 TDD를 수행하는 건 거의 불가능하다. 그림2 는 사람들이 xUnit tool을 어떻게 사용하는 지 보여주는 UML 상태 차트이다. 이 다이어그램은 Keith Ray가 제공했다.

XP에서 TDD를 대중화한 켄트 백은 TDD의 두가지 간단한 규칙을 정의했다. 첫째는 새로운 비즈니스 코드는 자동화된 테스트가 실패했을 경우에만 작성하는 것. 둘째는 중복은 찾는대로 제거하는 것이다. 켄트백은 이 두가지 간단한 규칙이 개인 집합과 단체에서 적용될지 다음과 같이 설명한다.
-
피드백을 제공하면서 수행하도록 코드를 유기적으로 설계하라.
-
자신만의 테스트를 작성하라. 다른 사람이 당신을 위해서 작성해주지는 않을 것이기 때문에 .
-
개발 환경은 반드시 작은 변화에 대해 빠른 응답을 줄 수 있도록 하라. (예. 빠른 컴파일러와 테스트 스위트의 수행 필요)
-
더 쉽게 테스트 하기 위하여 응집력 있되 느슨하게 결합하도록(고도의 정규화) 설계하라(이는 진보적이며 시스템의 관리도 쉽게 한다).
개발자들을 위하여, 효과적으로 단위 테스트를 작성하는 법을 정리하자면, 다음과 같은 켄트백의 경험이 도움이 될 것이다.
-
빨리 수행하라. (짧은 초기화, 수행시간, 해제를 가져야 한다.)
-
격리하여 실행하라 (순서를 섞을 수 있어야 한다.)
- 쉽게 읽고 이해할 수 있는 데이터를 사용하라.
-
필요한 경우 진짜 데이터(예. production의 사본)를 사용하라.
-
한 단계 진행은 최종목표를 나타낸다.
2. TDD와 전통적인 테스팅
TDD는 소스코드가 순전히 단위테스트되었음을 확인하는 기초적인 설계 기술이다. 더 많은 테스팅이 있을 수 있다. agile acceptance testing and investigative testing 같은 다른 테스팅이 필요할 것이다. 이러한 테스팅들은 그렇게 하기로 마음 먹었다면 프로젝트에 일찍 적용할 수 있다. 실제로, 사용자 스토리를 위한 XP acceptance 테스트들은 코드가 작성되기 이전이나 또는 진행중에 프로젝트 책임자에게 시스템이 요구사항과 일치한다는 신뢰를 줄 수 있다.
하나 또는 여러 개의 결함으로 부터 성공을 찾는 전통적인 테스팅은 사실 TDD와 같다. 테스트가 실패하면서 일을 진척시키기 때문에 문제를 해결하는데 필요한 것이 무엇인지 알게되기 때문이다. 더 중요한 것은 테스트가 더 이상 실패하지 않음으로서 성공을 위한 명백한 요소를 갖게 된다는 것이다. TDD는 시스템이 시스템이 정의된 요구사항과 실제로 일치하는 지에 대한 신뢰도를 증진 시킨다. 시스템은 실제로 작동되고, 그렇기 때문에 일에 자신감을 가질 수 있다.
전통적인 테스팅의 경우, 테스트가 필요할 경우 시스템의 손실을 예견하는 데 있어 뛰어나다. 전통적인 테스팅이나 TDD 모두 완벽하지는 않지만 시스템의 중요성을 위해 테스트 한다. “목적을 가진 테스트”와 왜 무언가를 테스팅하는가를 아는 것, 그리고 테스트되어야 할 수준은 무엇인가는 애자일 모델링(AM)이라고 바꾸어 말할 수 있다. TDD의 흥미로운 부작용은 전통적인 테스팅은 보장하지 못하는 “코드의 모든 줄이 테스트 되는” 100% 테스트 커버리지를 달성하는 것이다 (전통적인 테스팅은 이를 권장한다). 비록 TDD는 명세 기술일지라도 전통적인 기술로 테스팅하는 것보다는 훨씬 더 나은 코드 테스팅이라는 결과를 가지는, 가치있는 부작용도 동반한다고 생각한다.
|
3. TDD와 문서화
좋든 싫든 대부분의 프로그래머들은 시스템을 위해 작성된 문서를 읽지 않고, 코드를 보는 것을 선호한다. 그리고 이것은 잘못된 것이 아니다. 대부분의 프로그래머들은 클래스나 동작을 이해하기 위해 실행되는예제 코드를 찾을 것이다. 잘 작성된 단위 테스트들은 이것을 잘 할수 있다. (기능 코드의 업무 명세가 제공) 그리고 단위 테스트 결과는 기술 문서의 중요한 부분이 될 수 있을 것이다.
테스트들은 문서로 충분한가? 그렇지는 않지만, 중요한 부분이 될 수 있을 것이다. 예를 들면, 사용자, 시스템 개요, 운영, 지원 문서들을 찾을 것이다. 찾는다 하더라도 시스템이 지원하는 비즈니스 프로세스 개요 요약 문서가 필요하다. 열린 마음으로 문서에 접근한다해도, 예상컨데 개발자와 업무 책임자에게 필요한 대다수의 문서는 테스트가 커버함을 알 수 있을 것이다. 나아가, AM에서의 단일 소스 정보 원칙에 좋은 예제가 있고, 모든 범위에서 중요한 부분은 문서에 대해서 얼마나 기민(agile)하려고 노력하는 가이다.
4. 왜 TDD 인가?
TDD는 소프트웨어 작성시 작은 단계를 취하는 것만으로 이득을 얻을 수 있다. 커다란 단계의 코드를 시도하는 것보다 생산적이었기때문에 다년간 내가 발전할 수 있는 방법이었다. 예로, 몇몇 새로운 기능 코드를 추가하려고 할때, 컴파일 하고 테스트한다. 새로운 코드에 존재하는 결점에 의해 테스트들이 망가졌을 때가 기회이다. 그 결점들은 2,000 보다 2 줄을 작성했을 때, 훨씬 찾고 고치기 쉽다. 그 말인 즉, 컴파일러와 테스트 스위트 순환이 빠르다는 것이고, 작은 단계에서 수행하는게 매력적이라는 것이다. 필자는 테스트들을 재컴파일과 재실행하기에 앞서 보통 10줄 미만의 기능코드의 아주 적은 새로운 줄을 추가하는 편이다.
밥 마틴이 이에 대해 잘 이야기했다고 생각한다. “단위 테스트를 작성하는 행위은 검증 보다 설계이다. 또한 검증 보다는 문서화 하는 행위이다. 단위 테스트를 작성하는 행위는 놀랄만한 숫자의 피드백 루프, 하나의 기능 검증에 관련한 최소한이라 할 수 있다.”
애자일 기술을 가진 많은 사람들의 첫 반응은, 아마도, 소수의 사람들이 수개월에 걸쳐서 개발하는 작은 프로젝트에서는 괜찮지만 이보다 훨씬 대형의 “실제” 프로젝트에서는 하지 않으려 한다는 것이다. 간단히 이는 사실이 아니다. 켄트 백(2003)은 25만줄의 기능코드와 25만줄의 테스트코드를 배출한 40명의 인원이 4년간 투입된 완벽히 테스트 주도 접근을 취하는 스몰토크 시스템에서 일하고 있다고 했다. 하루에도 몇번씩 실행되며 전체가 20분 안에 실행되는 4000개의 테스트를 가지고 있다. 비록 그 만큼 큰 시스템이 아닐지라도 필자는 개인적으로 수년에 걸쳐 수백명이 투입되어 일하고 있는 시스템에서 일하고 있고, TDD를 하기에 아주 좋은 크기이다.
5. 미신과오해
가능하면 해소하고 싶은, 사람들이 TDD에 대해 가는 몇가지 미신과 오해가 있다. 표 1은 이러한 미신과 실제에 대한 목록이다.
표 1. TDD를 둘러싼 미신과 오해에 대한 규명.
| 오해 | 사실 |
| 당신은 테스트 스위트 를 100% 만들 수 있다. |
이 얘기가 정말 좋은 목표로 보일지라도 불행하게도 이것은 다음과 같은 이유때문에 그렇지 않다 :
|
| 단위테스트가 당신의 설계 명세를 100% 나타낸다. |
애자일 소프트웨어 개발에 새로 입문한 사람이나 애자일을 추구하지만 실제로는 그렇지 않거나 실제로는 애자일 프로젝트에 포함된 적은 없는 사람들은 그렇게 말한다. 사실은 단위테스트는 설계 명세의 아주 일부분만을 나타내지만 그 이상은 아니라는 것이다. 제품코드에 대해서 생각하기전에 작성하기 때문에 어떻게 할 것 인지에 대해서만 충분하다. |
| 오로지 단위테스트만 필요하다. | 아주 단순한 시스템을 제외한 모두에서 완전히 잘못되었다. 애자일 커뮤니티는 다른 테스팅 기술들이 매우 필요함에 대해 명백하다. |
| TDD는 테스팅에 충분하다. | 단위/개발자 테스트에서 TDD는 고객 테스트 수준에는 부합하지만 전체 테스팅분야의 일부일 뿐이다. 확인된 테스팅 분야를 조합하는 것이 최상이지만, 그림 4에서 보듯이 이것을 뛰어 넘기 위해 새로운 테스팅 분야를 연구하는 것을 게을리 하지 말아야 한다. 자세한 것은 Agile Testing Strategies를 참조. |
| TDD를 전파할 수 없다. |
부분적으로 사실이지만, 극복하기 쉽다. 전파 문제는 다음을 포함한다.
|






우와 대단.. 영어잘하네..ㅋ