테스트 주도 개발(TDD) - 개념편
in Devlog on Web, Bit
테스트 주도 개발 : Test-Driven Development by Example
추천 책 : 테스트 주도 개발 (켄트 백, 인사이트, 김창준 강규영 옮김)
TDD 개발에 대한 개념을 한번 짚고 넘어가기위한 글이다. 개인적으로 TDD에 대한 개념을 딱 와닿게 만들어준 글과 책이 있었다. (상단 참고_ 정리겸 다시 적어본다. TDD… 실제로 사용해보니 내가 딱 원하는 기능이더라
TDD란?
- 프로그램을 코드 단위로 잘게 쪼개서 실행해 볼 수 있는 좋은 방식이다. 단 테스트를 먼저 작성하는 것으로 코드가 동작하지 않는 상태임을 명확하게 확인한다.
- [TDD의 과정] 빌드가 되지 않는 상태에서 빨간불이 들어오도록 최소 코드를 작성 → 빨간 불을 초록불로 최대한 빠르게 바꾸기 위해 하드코딩도 서슴치 않고 사용 → 초록불이 들어온 후에 작성한 테스트를 통해 리팩토링
- 결과를 하드코딩 하는 것은 일반적으로 죄악으로 여겨지지만 필요할 때 사용할 수 있어야 한다. 이 단계를 생각지 않고 먼저 큰 코드를 작성하면 당장은 테스트의 단계를 줄일 수 있으나, 문제는 그렇게 작성한 코드가 생각대로 동작하지 않았을 때, 테스트 작성도 어려워지고 고민해야 할 단위도 커진다. 이럴때 다시 하드코딩 수준으로 돌아와 줘야 하는데 생각의 단위를 가볍게 돌리는 일은 쉽지 않다.
- 코딩이 안될 땐 쉬어야 한다는 이야기는 참 좋은 미덕이다.
테스트를 언제 작성하는 것이 좋을까? 테스트 대상이 되는 코드를 작성하기 직전에 작성하는 것이 좋다. (p.210)
- 나중에 작성하면 항상 통과하는 무의미한 테스트를 작성하게 될 수도 있다.
시스템을 개발할 때 무슨 일부터 하는가? 완료된 시스템이 어떨 거라고 알려주는 이야기부터 작성한다. 특정 기능을 개발할 때 무슨 일부터 하는가? 기능이 완료되면 통과할 수 있는 테스트 부터 작성한다. 테스트를 개발할 때 무슨 일부터 하는가? 완료될 때 통과해야 할 단언(assert)부터 작성한다. (p.211)
상향식, 하향식 둘 다 TDD 프로세스를 효과적으로 설명해 줄 수 없다. 첫째로 이와 같은 수직적 메타포는 프로그램이 시간에따라 어떻게 변해 가는지에 대한 단순화 된 시각일 뿐이다. 이보다 성장(growth) 이라는 단어를 보자. ‘성장’은 일종의 자기 유사성을 가진 피드백 고리를 암시하는데, 이 피드백 고리에서는 환경이 프로그램에 영향을 주고 프로그램이 다시 환경에 영향을 준다. 둘째로 만약 메타포가 어떤 방향성을 가질 필요가 있다면 (상향 혹은 하향보다는) ‘아는 것에서 모르는 것으로(known-to-unknown)’ 라는 방향이 유용할 것이다. ‘아는 것에서 모르는 것으로’는 우리가 어느 정도의 지식과 경험을 가지고 개발을 시작한다는 점, 개발하는 중에 새로운 것을 배우게 될 것임을 예상한다는 점을 암시한다. 이 두가지를 합쳐보자. 우리는 아는 것에서 모르는 것으로 성장하는 프로그램을 갖게 된다.
- TDD 프로세스는 첫째로 성장하는 프로세스이다. 둘째로 TDD가 방향성을 가질 필요가 있다면 상향, 하향보다는 ‘아는 것에서 모르는 것으로’ 라는 방향이 유용하다. ‘아는 것에서 모르는 것으로’란 우리가 어느 정도의 지식과 경험을 가지고 개발을 시작한다는 점, 개발 하는 중에 새로운 것을 배우게 될 것임을 예상한다는 점을 암시한다. 즉, 두가지를 합쳐보면 TDD를 통해 아는 것에서 모르는 것으로 성장하는 프로그램을 갖게 된다.
첫 걸음으로 현실적인 테스트를 하나 작성한다면 상당히 많은 문제를 한번에 해결해야 하는 상황이 될 것이다. …정말 발견하기 쉬운 입력과 출력을 사용하면 이 시간을 짧게 줄일 수 있다.(p. 219)
- 한번에 모든 것을 작성하려는 습관을 버려야 한다.
화이트 박스 테스트를 바라는 것은 테스팅 문제가 아니라 설계 문제다. 코드가 제대로 작동하는지를 판단하기 위한 용도로 변수를 사용하길 원한다면 언제나 설계를 향상할 수 있는 기회가 있다. 하지만 두려움 때문에 포기하고 그냥 변수를 사용하기로 결정해 버리면 이 기회를 잃게 된다. 그렇게 말하긴 했지만 정말 설계 아이디어가 떠오르지 않으면 어쩌겠는가. 그냥 변수를 검사하게 만들고 눈물을 닦은 후, 머리가 좀더 잘 돌아갈 때 다시 시도해보기 위해 적어놓고서 다음 작업을 진행할 것이다. (p. 255)
- 테스트를 작성하면서 테스트가 코드 내부 구현을 너무 많이 알고 있을때에는 코드에 의존적인 테스트를 작성하기 마련이다. 일단 테스트를 통과하면 일단 두고 넘어가자. 리팩토링에서 다시 만나면 코드를 새로 작성하거나 테스트를 새로 작성하면 된다.
‘관측상의 동치성’이 성립되려면 충분한 테스트를 가지고 있어야 한다. 여기에서 충분한 테스트란, 현재 가지고 있는 테스트들에 기반한 리팩토링이 추측 가능한 모든 테스트에 기반한 리팩토링과 동일한 것으로 여겨질 수 있는 상태를 말한다. (p. 292)
- 빨간 불에서 초록 불로 바꾸는 과정에서 관측 상의 동치성이 나타난다. 초록 불 상태에서 코드를 바꿔도 초록 불이라면 외부에서 보기엔 동일한 결과를 반환하기 때문에 문제가 없다. 때문에 초록 불 상태로 어떤 방식으로든 빠르게 만들어 내야 한다.
패턴 복사하기 자체는 훌륭한 프로그래밍이 아니다. 이 사실은 내가 패턴에 대해 이야기 할 때면 늘 강조한다. 패턴은 언제나 반숙 상태며, 자신의 프로젝트 오븐 속에서 적응시켜야 한다. 하지만 이렇게 하기 위한 좋은 방법 중 하나는 일단 무턱대고 패턴을 복사하고 나서, 리팩토링과 테스트 우선을 섞어 사용해서 그 적응과정을 수행하는 것이다. 패턴 복사를 할 때 이렇게 하면 해당 패턴에 대해서만 집중할 수 있게 된다(한 번에 하나씩). (p. 340)
- TDD와 리팩토링 과정 속에서 패턴은 자연스럽게 발견되어야 한다는 이야기와 유사하다. 패턴은 반숙이다.