TestDrivenDevelopment design

TestDrivenDevelopment design

원문 : http://www.martinfowler.com/bliki/TestDrivenDevelopment.html

테스트 주고 개발(TDD)는 테스트를 통해서 개발을 이끌어 내는 설계 기술이다. 본질적으로 다음 세 개의 단순한 단계를 반복하는 것이다.

•    다음으로 추가하고 싶은 기능을 위한 테스트를 작성한다.
•    테스트가 통과 하도록 기능 코드를 작성하라.
•    전체적으로 구조화 되도록 새로운 코드와 기존의 코드를 재구성한다.

시스템의 기능을 구현할 때 한번에 하나씩 테스트 하면서 지속적으로 이 세 단계를 반복한다. XPE2가 선 테스트 프로그래밍(Test First Programming)이라고 부르는 대로 Test를 먼저 작성하는 것은 두 가지 주요 장점이 있다. 그 중 가장 명백한 것으로 테스트를 통과하는 기능 코드만을 작성할 수 있기 때문에 자체 테스트 코드를 얻을 수 있다. 두 번째로 테스트를 먼저 생각하게 되면 코드의 인터페이스를 먼저 생각하게 된다. 인터페이스 그리고 클래스를 어떻게 사용할 것인지에 초점을 맞추는 것은 구현으로부터 인터페이스를 분리해 내는데 도움이 된다.

TDD의 효율성을 올리는 가장 흔한 방법으로 세 번째 단계를 생략하는 것이라고 들었다. 깔끔하게 유지하기 위해 코드를 재구성 하는 것은 TDD 프로세스의 핵심이다. 그렇게 하지 않으면 난잡한 코드 조각 덩어리들의 모임을 보게 될 것이다. (그래도 최소한 테스트는 가지고 있을 것이기 때문에 대부분의 설계 실패에 대한 고통보다는 덜 할 것이다.)

Introduction to TDD(번역중)

원문 : http://www.agiledata.org/essays/tdd.html

테스트 주도 개발은 선-테스트 개발(test를 먼저 작성하고 그 test를 만족시키지 위한 코드를 작성하는 개발 기법)과 리팩토링을 조합한 개발에 대한 진보적인 접근이다. TDD의 주요 목적은 무엇인가?
One view is the goal of TDD is specification and not validation (Martin,Newkirk, and Kess 2003). 다른 말로, 코드를 작성하기 전에 설계에 대해 생각하는 하나의 방법이라는 관점이다. 또다른 관점은 TDD는 프로그래밍 기술이라는 관점입니다. Ron Jeffries는 TDD의 목표가 제대로 동작하는 깰끔한 코드를 작성하는 것이라고 말한다.  나는 각각의  주장에 모두 장점이 있다고 생각하고 따라서 선택은 여러분에게 맡긴다.

Table of Contents
1. What is TDD
2. TDD and Traditional Testing

1. What is TDD?

선 테스트 개발의 과정은 UML의 활동 다이어그램으로 Figure1에 나타나있다. 가장 먼저 해야할 것은 test를 빨리 추가하는 것이고 기본적으로 fail이 되는 코드로 충분하다. 다음은 test를 실행한다. 속도 때문에 새로 추가된 test가 fail되는 것을 보기 위해 일부만 test 할 수도 있겠지만 보통은 전체를 test한다. 그리고 코드가 추가된 test를 통과하도록 수정한다. 네번째로 test를 다시 실행한다. 만약 test에 실패하면 코드를 다시 수정하고 다시 테스트한다. 테스트가 통과하면 다시 첫번째 단계로 돌아간다.(만약에 design결과 중복을 제거할 필요가 생겼다면 TFD에서 TDD로 전환할 필요가 있다.)

Figure1. The Step of Test-First Development

I like to describe TDD with this simple formula:

나는 TDD를 간단한 공식으로 표현하길 좋아한다:

   TDD = TFD + refactoring.

TDD는 전통적인 개발 방법을 완전히 바꿨다. 기능 코드를 먼저 작성하고 뒤늦게 테스트하는 코드를 작성하는 대신에 기능 코드를 작성하기 전에 테스트 코드를 작성한다. 게다가 이런 방법으로 매우 조금씩 개발해 나간다.(하나의 테스트가 하나의 기능에 대응되게 한다.) TDD 접근 방법을 받아들인 개발자는 기능 코드가 존재 하지 않기 떄문에 실패하는 테스트 코드가 존재하기 전까지 기능 코드를 작성하는 것을 거부한다. 그들은 기능 코드를 위한 테스트가 존재하지 않으면 단 한줄의 코드도 추가하려 들지 않는다. 테스트 코드가 존재하게 되는 순간 그들은 그 테스트가 패스 되도록 작업을 한다. (your new code may break several existing tests aswell as the new one). 코드가 제대로 작동하면 질을 향상 시키지 위해 리팩토링한다. 이론적으로는 매우 간단해 보이지만 처음 TDD 접근 방법을 배울 때는 상당한 훈련을 필요로 한다. 처음에는 test 코드 없이 기능 코드를 구현하거나 실수하기 쉽기 떄문이다. 짝 프로그래밍의 장점 중 하나 (Williams and Kessler 2002)는 짝꿍이 여러분을 이러한 훈련을 계속 하도록 지켜주기 때문이다.

여러분이 단위 테스트 프레임웍을 사용한다는 것이 TDD에 깔려있는 전제 조건이다. Agile 소프트웨어 개발자들은 보통 뭐Unit 식의 오픈소스 툴을 사용한다. JUnit이나 VBUnit같은 것을 사용하는데 물론 사용툴도 좋은 대안이 될 수있다. 이러한 툴 없이는 TDD는 사실상 불가능하다. Figure2는 UML의 상태 다이어그램으로 뭐Unit 툴들이 일반적으로 동작하는 방법을 보여주고 있다. 이 다이어그램은 Keith Ray에 의해 제안 되었다.

Figure2 Testing via the xUnit Framework.

XP(Beck2000)에서 TDD를 공표한 Kent Beck은 TDD를 위한 두 개의 간단한 법칙을 정의했다.(Beck2003) 하나, automated test가 실패했을 때만 새로운 비즈니스 코드를 작성하라. 둘, 찾아낸 어떠한 중복이라도 제거하라. Beck은 어떻게 이 두가지 단순한 법칙이 복잡한 개인과 그룹의 행동들을 발생시키는지 설명한다.

  • 여러 의견들 간의 피드백을 제공하는 코드를 가지고 유기적으로 설계하라.
  • 하루에 20시간은 누간가 자신을 위해 테스트 코드를 작성해 주길 기다리지 말고 직접 만들어라.
  • 사용하고 있는 개발 환경은 작은 변화에도 빠른 반응을 보여야 합니다.(빠른 컴파일러와 회기 테스트 suite이 필요합니다.)
  • 설계는 반드시 결합도가 높고(e.g. your design is highly normalized) 구성요소들 간의 종속성은 낮아야(this also makes evolution and maintenance of your system easier too) 쉽게 테스트 할 수 있다.

개발자들은 효율적인 단위 테스트를 어떻게 작성하는지 배우는 것이 필요하다. Beck’sexperience is that good unit tests:

  • Run fast (they have short setups, run times, and break downs).

  • Run in isolation (you should be able to reorder them).

  • Use data that makes them easy to read and to understand.

  • Use real data (e.g. copies of production data) when they need to.

  • Represent one step towards your overall goal.

TDD and Traditional Testing

2. TDD and Traditional Testing

TDD는 기본적으로 단위 테스트를 통해 자신의 소스 코드를 확인하는 효과를 가지고 있는 프로그래밍 기술이다. However, there is more to testing than this. 기능 테스트, 인수 테스트, 시스템 통합 테스트와 같은 전통적인 테스트 역시 고려할 필요가 있다. 이 들 테스트 중 대다수는 여러분이 하기로 선택했다면(또는 해야만 한다면) 프로젝트 초기에 끝낼 수 있을 것이다. 사실 XP에서 코드가 작성되기 전 또는 작성 되면서 프로젝트의 주요관계자들에 의해 사용자를 위한 인수 테스트는 명세된다. 이렇게 함으로써 프로젝트의 주요관계자들에게 시스템이 사용자의 요구사항을 만족시킬 것이라는 자신감을 주게된다.

전통적인 테스트에서 성동적인 테스트는 하나 또는 그 이상의 결점을 찾아낸다. TDD에서도 똑같다. 테스트가 실패하게 되면 문제를 해결할 필요가 있다는 것을 알았기 때문에 일을 진행하면 된다. 이보다 더 중요한 것은 테스트에 실패가 없을 때는 분명한 성공의 척도가 된다는 것이다. TDD는 개발하고 있는 시스템이 요구사항을 만족시키고 있다는 자신감을 증진시켜준다. 따라서 자신감을 가지고 일을 진행할 수 있다.

전통적인 테스트와 마찬가지로, 시스템의 위험 요소들이 많을 수록 많은 테스트가 요구된다. With both traditional testing and TDD you aren’tstriving for perfection, instead you are testing to the importance of thesystem. AgileModeling (AM)을 달리 말하자면, “목적을 가진 테스트”를 해야하고 왜 그것을 테스트 하고 있는지 그리고 어디까지 테스트 되어야 하는지를 알아야 한다. TDD의 흥미로운 부가적인 효과로 전통적인 테스트가 보장하지 못했던 100% 모든 코드에 대한 테스트를 할 수 있다는 것이다. 일반적으로 전통적인 테스트 기술보다 TDD의 결과물이 명백히 낫다고 말할 수 있다.

If it’s worth building, it’s worth testing.

If it’s not worth testing, why are you wasting your time working on it?