테스트 주도 개발
테스트 주도 개발(TDD)은 지속적인 설계 요소를 추가한 테스트 우선 프로그래밍의 특수한 경우입니다.
테스트 우선 프로그래밍에는 프로덕션 코드에 대한 자동화된 단위 테스트를 생성하는 것이 포함됩니다. 전에 프로덕션 코드를 작성합니다. 나중에 테스트를 작성하는 대신(또는 더 일반적으로는 테스트를 전혀 작성하지 않는 대신), 항상 단위 테스트로 시작합니다. 프로덕션 코드의 모든 작은 기능 청크에 대해 먼저 코드가 수행할 작업을 지정하고 검증하는 작고(이상적으로는 매우 작고) 집중적인 테스트를 빌드하고 실행합니다. 이 테스트는 필요한 모든 클래스와 메서드가 존재하지 않을 수 있으므로 처음에는 컴파일되지 않을 수도 있습니다. 그럼에도 불구하고 일종의 실행 가능한 사양으로 기능합니다. 그런 다음 최소한의 프로덕션 코드로 컴파일하여 실행하고 실패하는 것을 확인할 수 있습니다. (실패할 것으로 예상하고 통과하는 경우도 있는데, 이는 유용한 정보입니다.) 그런 다음 해당 테스트가 통과할 수 있도록 정확히 필요한 만큼의 코드를 생성합니다.
이 기법은 처음 시도하는 많은 프로그래머들에게 생소하게 느껴질 수 있습니다. 마치 암벽 등반가가 암벽을 조금씩 오르면서 닻을 내리는 것과 같습니다. 왜 이렇게 애를 써야 할까요? 분명 속도가 상당히 느려질 텐데 말이죠. 답은 나중에 단위 테스트에 반복적으로 의존하게 될 때에만 의미가 있다는 것입니다. 테스트 우선 방식을 꾸준히 실천하는 사람들은 단위 테스트가 작성에 들인 노력보다 훨씬 큰 보상을 준다고 주장합니다.
테스트 우선 작업의 경우, 일반적으로 자동화된 단위 테스트 프레임워크인 xUnit 계열(JUnit for Java, NUnit for C# 등) 중 하나를 사용합니다. 이러한 프레임워크를 사용하면 대규모 단위 테스트 모음을 생성, 실행, 구성 및 관리하는 것이 매우 간편해집니다. (적어도 Java 환경에서는 이러한 프레임워크가 최고의 IDE에 점점 더 잘 통합되고 있습니다.) 테스트 우선 작업에서는 단위 테스트가 엄청나게 누적되기 때문에 이는 좋은 방법입니다.
테스트 우선 작업의 이점
철저한 자동화된 단위 테스트 세트는 버그 탐지를 위한 일종의 그물 역할을 합니다. 시스템의 현재 동작을 정확하고 확실하게 파악합니다. 우수한 테스트 우선 팀은 시스템 수명 주기 전체에서 결함 발생률이 상당히 낮고 디버깅 시간도 훨씬 단축됩니다. 잘 작성된 단위 테스트는 또한, 당연히 프로덕션 코드와 항상 동기화되는 훌륭한 설계 문서 역할을 합니다. 다소 예상치 못한 이점은 많은 프로그래머가 모든 테스트가 정상적으로 실행되고 있음을 나타내는 "작은 녹색 막대"가 중독성이 있다는 것입니다. 코드 상태에 대한 이러한 작고 빈번한 긍정적인 피드백에 익숙해지면 포기하기가 정말 어렵습니다. 마지막으로, 코드의 동작이 수많은 훌륭한 단위 테스트로 확인되면 훨씬 더 효과적입니다. safe당신을 위해 r 코드를 리팩토링하다리팩토링(또는 성능 조정이나 다른 변경 사항)으로 인해 버그가 발생하면 테스트에서 신속하게 알림을 받습니다.
테스트 주도 개발: 한 단계 더 발전시키기
테스트 주도 개발(TDD)은 테스트 우선 프로그래밍의 특수한 사례로, 지속적인 설계라는 요소를 더합니다. TDD를 사용하면 시스템 설계가 종이 설계 문서에 얽매이지 않습니다. 대신 테스트 및 프로덕션 코드 작성 프로세스를 통해 설계를 진행해 나갈 수 있습니다. 몇 분마다 리팩토링을 통해 단순화하고 명확하게 만듭니다. 더 명확하고 깔끔한 메서드, 클래스 또는 전체 객체 모델을 쉽게 떠올릴 수 있다면, 그 방향으로 리팩토링하고, 견고한 단위 테스트 모음으로 처음부터 끝까지 보호합니다. TDD의 기본 전제는 코드를 팔꿈치까지 파고들기 전까지는 어떤 설계가 가장 적합한지 알 수 없다는 것입니다. 실제로 무엇이 효과적이고 무엇이 효과적이지 않은지 알아가면서, 그 통찰력이 아직 머릿속에 생생할 때 적용할 수 있는 최적의 위치에 있게 됩니다. 그리고 이 모든 활동은 자동화된 단위 테스트 모음으로 보호됩니다.
상당히 많은 양의 사전 설계로 시작할 수 있지만 일반적으로는 상당히 많은 양의 사전 설계로 시작하는 것이 더 일반적입니다. 간단한 코드 디자인; 극한 프로그래밍 세계에서는 화이트보드 UML 스케치 몇 개면 충분합니다. 하지만 TDD에서는 처음에 얼마나 많은 디자인을 가지고 시작하느냐보다, 진행하면서 얼마나 디자인이 시작점에서 벗어나도록 허용하느냐가 더 중요합니다. 아키텍처를 전면적으로 변경하지는 않더라도, 가장 현명한 선택이라고 생각된다면 객체 모델을 상당 부분 리팩토링할 수 있습니다. 어떤 회사들은 다른 회사들보다 진정한 TDD를 구현할 정치적 자유도가 더 높습니다.
테스트 우선 vs. 디버깅
테스트를 미리 작성하는 데 드는 노력과 디버깅에 소요되는 시간을 비교해 보는 것이 유용합니다. 디버깅에는 종종 많은 양의 코드를 살펴보는 것이 포함됩니다. 테스트 우선 작업을 통해 작은 덩어리에 집중할 수 있어 오류가 발생할 가능성이 줄어듭니다. 관리자는 디버깅에 실제로 얼마나 걸릴지 예측하기 어렵습니다. 그리고 어떤 의미에서는 디버깅에 많은 노력이 낭비됩니다. 디버깅에는 시간 투자, 스캐폴딩, 그리고 기본적으로 모두 폐기 가능한 인프라(중단점, 임시 변수 감시, 출력 문)가 필요합니다. 버그를 찾아 수정하면 모든 분석 결과가 손실됩니다. 그리고 완전히 손실되지는 않더라도 해당 코드를 유지 관리하거나 확장하는 다른 프로그래머는 확실히 손실을 입습니다. 테스트 우선 작업을 통해 모든 사람이 테스트를 영원히 사용할 수 있습니다. 버그가 다시 나타나면 이전에 버그를 포착했던 동일한 테스트가 다시 버그를 포착할 수 있습니다. 일치하는 테스트가 없어서 버그가 발생하면 그 이후로 버그를 포착하는 테스트를 작성할 수 있습니다. 이런 식으로 많은 테스트 우선 실무자들은 그것이 더 열심히 일하는 대신 더 똑똑하게 일하는 전형이라고 주장합니다.
테스트 우선 기술 및 도구
시스템 동작의 모든 측면에 대한 단위 테스트를 작성하는 것은 항상 간단한 일이 아닙니다. GUI는 어떻습니까? 컨테이너 기반 프레임워크에서 수명이 관리되는 EJB 및 기타 생물은 어떻습니까? 데이터베이스와 일반적인 지속성은 어떻습니까? 예외가 제대로 발생하는지 어떻게 테스트합니까? 성능 수준은 어떻게 테스트합니까? 테스트 커버리지, 테스트 세분성 및 테스트 품질을 어떻게 측정합니까? 이러한 질문은 끊임없이 진화하는 도구와 기술 세트로 테스트 우선 커뮤니티에서 답변하고 있습니다. 단위 테스트를 통해 시스템 동작의 모든 측면을 다룰 수 있도록 엄청난 독창성이 계속해서 쏟아지고 있습니다. 예를 들어, 가짜 및 모의 객체를 사용하여 협력자 및 외부 리소스와 격리된 시스템 구성 요소를 테스트하는 것이 종종 합리적입니다. 이러한 모의 또는 가짜가 없으면 단위 테스트에서 테스트 중인 객체를 인스턴스화하지 못할 수 있습니다. 네트워크 연결, 데이터베이스, GUI와 같은 외부 리소스의 경우, 테스트에서 실제 리소스를 사용하면 속도가 크게 저하될 수 있지만, 가짜 또는 모의 버전을 사용하면 메모리에서 모든 것이 빠르게 실행됩니다. 기능의 일부 측면에서는 항상 수동 테스트, 그것이 확실히 사실인 비율은 계속해서 줄어들고 있습니다.