테스트 주도의 개발

Test-driven development

TDD(Test-Driven Development)는 소프트웨어가 완전히 개발되기 전에 소프트웨어 요건을 테스트 케이스로 변환하여 모든 테스트 케이스에 대해 소프트웨어를 반복 테스트함으로써 모든 소프트웨어 개발을 추적하는 소프트웨어 개발 프로세스입니다.이는 소프트웨어가 먼저 개발되고 테스트 케이스가 나중에 작성되는 것과 반대됩니다.

이 기술을 개발 또는 "재발견"[1]한 것으로 알려진 소프트웨어 엔지니어 Kent Beck는 2003년에 TDD가 단순한 디자인을 장려하고 [2]자신감을 불어넣는다고 말했습니다.

테스트 주도의 개발은 [3]1999년에 시작된 익스트림 프로그래밍의 테스트 우선 개념과 관련이 있지만, 최근에는 그 [4]권리에 대한 일반적인 관심이 더욱 높아지고 있습니다.

프로그래머는 오래된 [5]기술로 개발된 레거시 코드를 개선하고 디버깅하는 데도 이 개념을 적용합니다.

테스트 주도의 개발 사이클

테스트 주도의 개발 라이프 사이클을 그래픽으로 표시

다음 순서는 테스트 중심 개발(Test-Driven Development by Example)[2]을 기반으로 합니다.

1. 테스트 추가
새로운 기능의 추가는 기능의 사양이 충족될 경우 합격하는 테스트를 작성하는 것으로 시작됩니다.개발자는 사용 사례사용자 사례를 물어봄으로써 이러한 사양을 발견할 수 있습니다.테스트 중심 개발의 주요 장점은 개발자가 코드를 작성하기 전에 요건에 집중할 수 있다는 것입니다.이는 장치 테스트가 코드 뒤에만 기록되는 일반적인 관행과는 대조적입니다.
2. 모든 테스트를 실행합니다.예상된 이유로 새 테스트가 실패할 수 있습니다.
이것은, 실제로 필요한 기능에 새로운 코드가 필요한 것을 나타내고 있습니다.테스트 하니스가 올바르게 작동하는지 확인합니다.그것은 새로운 시험에 결함이 있고 항상 합격할 가능성을 배제한다.
3. 새로운 테스트를 통과한 가장 간단한 코드를 작성합니다.
테스트에 합격하는 한, 품위 없는 코드나 하드 코드는 허용됩니다.코드는 스텝 5에서 연마됩니다.테스트 끝난 기능 이외에는 코드를 추가하지 말아 주세요.
4. 이제 모든 테스트가 합격해야 합니다.
실패할 경우 통과될 때까지 새 코드를 수정해야 합니다.이를 통해 새 코드가 테스트 요건을 충족하고 기존 기능을 중단하지 않습니다.
5. 필요에 따라 리팩터(각 리팩터 후 테스트를 사용하여 기능성을 확보)
코드는 가독성과 유지보수성을 위해 리팩터링됩니다.특히 하드 코딩된 테스트 데이터는 삭제해야 합니다.각 리팩터 후에 테스트 스위트를 실행하면 기존 기능이 중단되지 않도록 할 수 있습니다.
따라하다
위의 사이클은 새로운 기능의 각 부분에 대해 반복됩니다.테스트는 작고 증분적이어야 하며 자주 커밋해야 합니다.따라서 새로운 코드가 일부 테스트에 실패하면 프로그래머는 과도하게 디버깅하는 대신 단순히 실행 취소 또는 복귀를 할 수 있습니다.외부 라이브러리를 사용할 때는 라이브러리가 버그가 있거나 개발 중인 소프트웨어의 모든 요구를 충족시킬 수 있을 만큼 기능이 풍부하지 않다고 판단할 이유가 없는 [4]한 라이브러리 자체를 효과적으로 테스트하기 위한 작은 테스트를 작성하지 않는 것이 중요합니다.

개발 스타일

테스트 주도의 개발에는, 「간단하고 멍청하게 한다」(KISS)나 「YAGNI」(YAGNI)의 원칙 등, 여러가지 측면이 있습니다.테스트를 통과하기 위해 필요한 코드만 작성하는 것에 집중함으로써 [2]디자인은 다른 방법보다 더 깨끗하고 명료할 수 있습니다.Kent Beck는 Test-Driven Development by Example에서 "Fake it to you make it"이라는 원칙을 제안합니다.

설계 패턴과 같은 고급 설계 개념을 달성하기 위해 해당 설계를 생성하는 테스트를 작성합니다.코드는 대상 패턴보다 단순하지만 필요한 테스트는 모두 통과합니다.이것은 처음에는 불안할 수 있지만 개발자는 중요한 것에만 집중할 수 있습니다.

먼저 테스트 쓰기:테스트는 테스트할 기능 전에 작성해야 합니다.이것은 많은 이점을 가지고 있다고 주장되어 왔다.개발자는 나중에 애플리케이션을 추가하는 것이 아니라 처음부터 테스트 방법을 고려해야 하기 때문에, 애플리케이션이 테스트 가능한 상태로 작성되도록 하는 데 도움이 됩니다.또, 모든 기능의 테스트가 확실히 기입됩니다.또한 테스트를 먼저 작성하면 제품 요건을 보다 깊이 있게 조기에 이해할 수 있으며 테스트 코드의 유효성을 확보하고 소프트웨어 [6]품질에 지속적으로 초점을 맞출 수 있습니다.기능 우선 코드를 작성할 때 개발자와 조직은 테스트를 완전히 무시한 채 개발자에게 다음 기능을 사용하도록 강요하는 경향이 있습니다.첫 번째 TDD 테스트는 필요한 클래스 및 메서드가 아직 존재하지 않을 수 있기 때문에 처음에는 컴파일조차 하지 않을 수 있습니다.단, 이 첫 번째 테스트는 실행 가능한 [7]사양의 시작 부분으로 기능합니다.

각 테스트 케이스는 처음에 실패합니다.이렇게 하면 테스트가 제대로 작동하고 오류를 발견할 수 있습니다.이것이 표시되면 기본 기능을 구현할 수 있습니다.이 때문에, 「테스트에 의한 개발의 모트라」(빨간색/녹색/리팩터)는, 「빨간색/녹색/리팩터」(빨간색/녹색)는 실패, 녹색은 합격의미)가 되고 있습니다.테스트 주도의 개발은 불합격 테스트 케이스를 추가하고 합격시킨 후 리팩터링하는 단계를 지속적으로 반복합니다.각 단계에서 예상되는 테스트 결과를 받으면 개발자의 코드 멘탈 모델이 강화되고 신뢰도가 높아지며 생산성이 향상됩니다.

유닛을 작게 유지하다

TDD의 경우 유닛은 클래스 또는 관련 함수의 그룹으로 정의되는 경우가 많습니다.유닛을 비교적 작게 유지하면 다음과 같은 중요한 이점을 얻을 수 있습니다.

  • 디버깅 작업 감소– 테스트 실패가 검출되었을 때 유닛 수를 작게 하면 오류를 추적하는 데 도움이 됩니다.
  • 자가 문서화 테스트– 소규모 테스트 케이스가 읽기 쉽고 [6]이해하기 쉽습니다.

테스트 중심 개발의 고도의 프랙티스는 고객이 지정한 기준을 수용 테스트로 자동화하여 기존의 유닛 테스트 중심 개발([8]UTDD) 프로세스를 추진하는 예를 들어 수용 테스트 중심 개발(ATDD) 및 사양으로 이어질 수 있습니다.이 프로세스를 통해 고객은 소프트웨어가 고객의 요건을 충족하는지 여부를 자동으로 판단할 수 있습니다.ATDD를 통해 개발팀은 고객이 각 사용자 사례에서 진정으로 원하는 것에 지속적으로 초점을 맞추는 수용 테스트라는 특정 목표를 충족할 수 있게 되었습니다.

베스트 프랙티스

테스트 구조

테스트 케이스의 효과적인 레이아웃을 통해 필요한 모든 작업이 완료되고 테스트 케이스의 가독성이 향상되며 실행 흐름이 원활해집니다.일관된 구조는 자가 문서화 테스트 케이스를 구축하는 데 도움이 됩니다.(1) 셋업, (2) 실행, (3) 검증 및 (4) 청소가 공통적으로 적용되는 테스트 케이스 구조이다.

  • 설정: 테스트 대상 유닛(UUT) 또는 전체 테스트 시스템을 테스트 실행에 필요한 상태로 만듭니다.
  • 실행:UUT를 트리거/구동하여 목표 동작을 수행하고 반환 값 및 출력 파라미터와 같은 모든 출력을 캡처합니다.이 단계는 보통 매우 간단합니다.
  • 검증:테스트 결과가 올바른지 확인합니다.이러한 결과에는 UUT 실행 중 또는 상태 변경 중에 캡처된 명시적 출력이 포함될 수 있습니다.
  • 청소:UUT 또는 전체 테스트 시스템을 테스트 전 상태로 복원합니다.이 복원을 통해 이 테스트 직후에 다른 테스트를 실행할 수 있습니다.경우에 따라서는 가능한 테스트 실패 분석의 정보를 보존하기 위해 청소가 테스트 셋업 실행 직전에 테스트를 시작해야 합니다.[6]

개별 베스트 프랙티스

개인이 따를 수 있는 베스트 프랙티스는 일반적인 셋업 로직과 해체 로직을 적절한 테스트 케이스에서 사용하는 테스트 지원 서비스로 분리하여 각 테스트 오라클을 테스트 검증에 필요한 결과에만 집중시키고 실시간이 아닌 운용 시에 실행할 수 있도록 시간 관련 테스트를 설계하는 것입니다.g시스템통상적으로 5~10%의 마진을 허용함으로써 테스트 실행 시 발생할 수 있는 오음성의 수를 줄일 수 있습니다.또한 테스트 코드를 제품 코드와 동일하게 취급할 것을 권장합니다.테스트 코드는 양성과 음성의 경우 모두 올바르게 작동해야 하며, 장시간 지속되며 판독 가능하고 유지보수가 가능해야 합니다.팀은 테스트와 테스트 연습을 함께 검토하여 효과적인 기술을 공유하고 [9]나쁜 습관을 발견할 수 있습니다.

피해야 할 관행 또는 "안티 패턴"

  • 테스트 케이스는 이전에 실행된 테스트 케이스에서 조작한 시스템 상태에 따라 달라집니다(즉, 항상 알려진 사전 구성 상태에서 장치 테스트를 시작해야 합니다).
  • 테스트 케이스 간의 의존성.테스트 케이스가 서로 의존하는 테스트 스위트는 부서지기 쉽고 복잡합니다.실행 순서를 추정해서는 안 됩니다.UUT의 초기 테스트 사례 또는 구조의 기본적인 리팩터링은 관련 테스트에서 점점 더 광범위하게 영향을 미치는 소용돌이를 일으킨다.
  • 상호의존 테스트상호의존 테스트로 인해 폴스 네거티브가 연속적으로 발생할 수 있습니다.초기 테스트 케이스에 장애가 발생하면 실제 장애가 UUT에 존재하지 않더라도 이후의 테스트 케이스가 파손되어 결함 분석 및 디버깅 작업이 증가합니다.
  • 정확한 실행 타이밍 또는 성능을 테스트합니다.
  • "모든 것을 아는 신탁"을 만들고 있다.필요 이상으로 검사하는 오라클은 시간이 지남에 따라 비용이 더 많이 들고 불안정해집니다.이 매우 일반적인 오류는 복잡한 [9][clarification needed]프로젝트 전체에 미묘하지만 광범위한 시간 낭비를 일으키기 때문에 위험합니다.
  • 구현 상세 테스트
  • 테스트 실행이 느리다.

혜택들

2005년의 한 연구에 따르면 TDD를 사용하면 더 많은 테스트를 작성할 수 있으며, 결과적으로 더 많은 테스트를 작성하는 프로그래머가 더 [10]생산적인 경향을 보였다.코드 품질 및 TDD와 생산성 간의 보다 직접적인 상관관계에 관한 가설은 결론을 [11]내리지 못했습니다.

새로운("그린필드") 프로젝트에서 순수 TDD를 사용하는 프로그래머들은 디버거를 실행할 필요성을 거의 느끼지 못했다고 보고했습니다.버전 관리 시스템과 함께 사용하면 테스트가 예기치 않게 실패했을 때 코드를 모든 테스트를 통과한 마지막 버전으로 되돌리는 것이 디버깅보다 [12]더 생산적일 수 있습니다.

테스트 주도의 개발은 단순한 정확성 검증 이상의 것을 [13]제공하지만 프로그램 설계를 추진할 수도 있습니다.먼저 테스트 케이스에 초점을 맞추면 클라이언트가 이 기능을 어떻게 사용할지 상상해야 합니다(첫 번째 케이스는 테스트 케이스).따라서 프로그래머는 구현 전에 인터페이스에 관심을 가집니다.이 편익은 수학적 주장이나 선입견이 아닌 테스트 사례를 통해 코드에 접근하기 때문에 계약에 의한 설계를 보완한다.

테스트 주도의 개발은 필요에 따라 작은 단계를 밟을 수 있는 기능을 제공합니다.첫 번째 목표는 시험에 합격하는 것이므로 프로그래머가 당면한 과제에 집중할 수 있도록 한다.예외적인 경우 및 오류 처리는 처음에는 고려되지 않으며 이러한 외부 환경을 조성하기 위한 테스트는 별도로 구현됩니다.테스트 주도의 개발을 통해 작성된 모든 코드가 적어도1개의 테스트로 커버됩니다.이것에 의해, 프로그래밍 팀과 그 이후의 유저에게 코드에 대한 신뢰도가 높아집니다.

유닛 테스트코드 때문에 TDD가 없는 경우보다 TDD에 더 많은 코드가 필요한 것은 사실이지만, 총 코드 구현 시간은 뮐러와 [14]Padberg의 모델에 따라 더 짧을 수 있습니다.많은 수의 테스트는 코드의 결점 수를 제한하는 데 도움이 됩니다.테스트의 초기 및 빈번한 성격은 개발 사이클의 초기에 결함을 발견하는 데 도움이 되며, 결함이 고질적이고 비용이 많이 드는 문제가 되는 것을 방지합니다.프로세스 초기에 결함을 제거하면 일반적으로 프로젝트 후반부에서 길고 지루한 디버깅을 피할 수 있습니다.

TDD는 보다 모듈화되고 유연하며 확장 가능한 코드를 만들 수 있습니다.방법론에서는 개발자가 소프트웨어를 독립적으로 작성 및 테스트하고 나중에 함께 통합할 수 있는 작은 단위로 생각할 것을 요구하기 때문에 이러한 영향이 종종 발생한다.이것에 의해, 보다 작고, 보다 집중적인 클래스, 보다 느슨한 커플링, 및 보다 깨끗한 인터페이스가 실현됩니다. 패턴은 유닛 테스트용 모의 버전과 전개용 "실제" 버전 간에 모듈을 쉽게 전환할 수 있도록 코드를 작성해야 하기 때문에 모의 객체 설계 패턴의 사용도 코드의 전체적인 모듈화에 기여합니다.

불합격 테스트 케이스에 합격하기 위해 필요한 코드보다 많은 코드가 작성되지 않기 때문에 자동 테스트는 모든 코드 경로를 커버하는 경향이 있습니다.예를 들어, TDD 개발자가 TDD 개발자를 위해else기존과 분기하다if기술, 개발자는 먼저 지점에 동기를 부여하는 불합격 테스트 케이스를 작성해야 합니다.그 결과, TDD에 의한 자동 테스트는 매우 철저한 경향이 있습니다.즉, 코드 동작의 예기치 않은 변화를 검출합니다.이를 통해 개발 주기의 후반에 변경 사항이 발생하면 다른 기능이 예기치 않게 변경될 수 있는 문제가 감지됩니다.

Madeyski는[15] 객체 간 하위 결합(CBO)과 관련하여 기존의 테스트-라스트 접근법 또는 정확성 접근법에 대한 테스트보다 TDD 실행의 우수성에 대한 경험적 증거를 제공했다.평균 효과 크기는 수행된 실험의 메타 분석에 기초한 중간(그러나 큰 것에 가까운) 효과를 나타내며, 이는 상당한 발견이다.TDD 프로그래밍 관행으로 [15]인해 개발된 소프트웨어 제품의 모듈화(즉, 모듈화 설계)가 개선되고 재사용 및 테스트가 쉬워집니다.또한 Madeyski는 장치 테스트의 정밀도와 고장 감지 효과를 나타내는 분기 탐지 범위(BC)와 돌연변이 점수 표시기(MSI)[16][17][18]를 사용하여 TDD 연습이 장치 테스트에 미치는 영향을 측정했습니다.지점 커버리지에 대한 TDD의 영향 크기는 중간 크기였기 때문에 실질적인 [15]효과로 간주됩니다.이러한 결과는 이후 TDD에 [19][20][21][22]대한 더 작은 실험 평가를 통해 확인되었다.

제한 사항

테스트 [23]주도 개발은 유닛 테스트의 광범위한 사용으로 인해 성공 또는 실패를 판단하기 위해 완전한 기능 테스트가 필요한 상황에서는 충분한 테스트를 수행하지 않습니다.예를 들어 사용자 인터페이스, 데이터베이스와 함께 작동하는 프로그램 및 특정 네트워크 구성에 의존하는 프로그램 등이 있습니다.TDD는 개발자들이 그러한 모듈에 최소한의 코드를 넣고 테스트 가능한 라이브러리 코드에 있는 논리를 극대화하도록 장려하고, 외부 세계를 [24]나타내기 위해 가짜와 모크를 사용한다.

관리 지원은 필수적입니다.테스트 주도의 개발이 제품을 개선할 것이라고 조직 전체가 믿지 않으면 경영진은 테스트 작성에 소비한 시간이 [25]낭비된다고 느낄 수 있습니다.

테스트 주도의 개발 환경에서 작성된 유닛 테스트는 일반적으로 테스트 대상 코드를 작성하는 개발자에 의해 작성됩니다.따라서 테스트에서는 코드와 사각지대를 공유할 수 있습니다.예를 들어 개발자가 특정 입력 파라미터를 확인해야 한다는 것을 깨닫지 못하면 테스트도 코드도 이러한 파라미터를 검증하지 못할 가능성이 높습니다.또 다른 예로는 개발자가 개발 중인 모듈의 요건을 잘못 해석하면 코드와 유닛 테스트가 모두 같은 방식으로 잘못됩니다.그러므로, 테스트는 합격할 것이고, 잘못된 정확성을 줄 것이다.

유닛 테스트에 합격하는 횟수가 많으면 보안에 대한 잘못된 인식이 생겨 통합 테스트나 컴플라이언스 테스트 등의 추가 소프트웨어 테스트 액티비티가 적어질 수 있습니다.

테스트는 프로젝트의 유지관리 오버헤드의 일부가 됩니다.하드 코딩된 오류 문자열을 포함하는 테스트 등 잘못 작성된 테스트는 그 자체로 실패할 가능성이 높으며 유지 보수 비용이 많이 듭니다.이것은 특히 [26]취약한 테스트의 경우에 해당됩니다.정기적으로 false failure를 생성하는 테스트가 무시될 위험이 있으므로 실제 failure가 발생했을 때 검출되지 않을 수 있습니다.예를 들어 오류 문자열을 재사용하는 등 유지보수가 간단하고 낮은 테스트를 작성할 수 있습니다.이 테스트는 위에서 설명한 코드 리팩터링 단계에서의 목표가 됩니다.

과도한 수의 테스트를 작성하고 유지하려면 시간이 필요합니다.또한 유연성이 높은 모듈(제한된 테스트 포함)은 테스트를 변경할 필요 없이 새로운 요건을 수용할 수 있습니다.이러한 이유로 극단적인 조건 또는 소수의 데이터 샘플에 대한 테스트는 매우 상세한 테스트 세트보다 쉽게 조정할 수 있습니다.

TDD 사이클 반복 중에 달성된 커버리지 및 테스트 세부 수준은 나중에 쉽게 재현할 수 없습니다.따라서, 이러한 독창적인 혹은 초기의 테스트는 시간이 지날수록 점점 더 소중해진다.그 전략은 그것을 일찍 고치는 것이다.또한 아키텍처, 설계, 테스트 전략이 좋지 않아 변경이 늦어져 수십 개의 기존 테스트가 실패할 경우 개별적으로 수정하는 것이 중요합니다.단순히 삭제, 비활성화 또는 경솔한 변경만으로 테스트 적용범위에 검출할 수 없는 구멍이 생길 수 있습니다.

테스트 주도의 작업

테스트 주도의 개발은 소프트웨어 개발 이외의 제품 팀과 서비스 팀 모두에서 테스트 주도의 [27]작업으로 채택되고 있습니다.TDD와 마찬가지로 비소프트웨어 팀은 작업을 시작하기 전에 작업의 각 측면에 대해 품질관리(QC) 검사(일반적으로 자동 테스트가 아닌 수동 테스트)를 개발합니다.그런 다음 이러한 QC 체크를 사용하여 설계에 정보를 제공하고 관련 결과를 검증합니다.TDD 시퀀스의 6단계에는 약간의 의미변경이 적용됩니다.

  1. "Add a test"가 "Add a test"로 바뀝니다.
  2. "Run all checks"가 "Run all tests"로 대체됩니다.
  3. "일부 코드 쓰기" 대신 "작업 수행"이 사용됩니다.
  4. "Run all checks"가 "Run tests"로 바뀝니다.
  5. "작업 정리"가 "리팩터 코드"를 대체합니다.
  6. '반복'

TDD 및 ATDD

테스트 주도 개발은 수용 테스트 주도 개발(ATDD)[28]과 관련이 있지만, 수용 테스트 주도 개발(ATDD)과는 다릅니다.TDD는 주로 일련의 작업을 올바르게 수행하는 코드 단위(함수, 클래스 또는 모듈)를 적절하게 작성하는 데 도움이 되는 개발자 도구입니다.ATDD는 고객, 개발자 및 테스터 간의 커뮤니케이션 도구로서 요건이 명확하게 정의되어 있는지 확인합니다.TDD에는 테스트 자동화가 필요합니다.ATDD는 그렇지 않지만 자동화는 회귀 테스트에 도움이 됩니다.코드 유닛이 요건의 일부를 구현하기 때문에 TDD에서 사용되는 테스트는 ATDD 테스트에서 파생되는 경우가 많습니다.ATDD 테스트는 고객이 읽을 수 있어야 합니다.TDD 테스트는 필요 없습니다.

TDD 및 BDD

BDD(Behavior-drived [29]development)는 TDD와 ATDD의 프랙티스를 조합한 것입니다.먼저 테스트를 작성하는 방법을 포함하지만, 구현 단위를 테스트하는 테스트보다는 동작을 설명하는 테스트에 초점을 맞춥니다.JBehave, Ooy, MspecSpecflow와 같은 도구는 제품 소유자, 개발자 및 테스트 엔지니어가 함께 동작을 정의하여 자동 테스트로 변환할 수 있는 구문을 제공합니다.

코드 가시성

테스트 스위트 코드는 테스트 중인 코드에 액세스할 수 있어야 합니다.한편, 정보 은닉, 캡슐화 및 우려사항의 분리같은 일반적인 설계 기준은 타협되어서는 안 된다.따라서 TDD의 유닛 테스트 코드는 보통 테스트 대상 코드와 동일한 프로젝트 또는 모듈 내에 작성됩니다.

객체 지향 설계에서는 여전히 개인 데이터 및 메서드에 대한 액세스를 제공하지 않습니다.따라서 유닛 테스트에 추가 작업이 필요할 수 있습니다.Java 및 기타 언어에서 개발자는 리플렉션을 사용하여 개인 필드 및 [30]메서드에 액세스할 수 있습니다.또는 내부 클래스를 사용하여 단위 테스트를 유지할 수 있으므로 해당 클래스의 멤버와 속성을 확인할 수 있습니다.에서.NET Framework 및 기타 프로그래밍 언어, 부분 클래스를 사용하여 테스트에 액세스하기 위한 개인 메서드 및 데이터를 노출할 수 있습니다.

이러한 테스트 해킹이 프로덕션 코드에 남아 있지 않도록 하는 것이 중요합니다.C 및 기타 언어에서는 다음과 같은 컴파일러 명령어를 사용합니다.#if DEBUG ... #endif이러한 추가 클래스 및 기타 모든 테스트 관련 코드 주위에 배치하여 릴리스된 코드로 컴파일되지 않도록 할 수 있습니다.이는 릴리스된 코드가 테스트된 장치와 완전히 동일하지 않음을 의미합니다.최종 릴리스 빌드에 대해 보다 적은 수의 포괄적인 엔드 투 엔드 통합 테스트를 정기적으로 실행하면 테스트 하니스의 측면에 미묘하게 의존하는 프로덕션 코드가 존재하지 않습니다.

블로그나 다른 글에 기록되어 있는 TDD의 실무자들 사이에서는 개인 방법이나 데이터를 테스트하는 것이 현명한지에 대한 논쟁이 있다.일부 사람들은 민간 구성원들이 바뀔 수 있는 단순한 시행 세부 사항이며, 시험 횟수를 어기지 않고 그렇게 하도록 허용해야 한다고 주장한다.따라서 퍼블릭인터페이스 또는 서브클래스인터페이스를 통해 클래스를 테스트하는 것으로 충분합니다.이러한 인터페이스를 [31]「보호」인터페이스라고 부르는 언어도 있습니다.또 다른 사람들은 기능의 중요한 측면이 민간 방법으로 구현될 수 있으며, 이러한 요소들을 직접 테스트하는 것이 더 작고 직접적인 단위 [32][33]테스트의 이점을 제공한다고 말한다.

TDD용 소프트웨어

TDD에는 많은 테스트 프레임워크와 툴이 도움이 됩니다.

xUnit 프레임워크

개발자는 일반적으로 집합적으로 xUnit이라고 하는 컴퓨터 지원 테스트 프레임워크를 사용하여 테스트 케이스를 작성하고 자동으로 실행할 수 있습니다.xUnit 프레임워크는 어설션 스타일의 테스트 검증 기능과 결과 보고를 제공합니다.이러한 기능은 실행 검증에 대한 부담을 독립된 사후 처리 활동에서 테스트 실행에 포함된 작업으로 옮기기 때문에 자동화에 매우 중요합니다.이러한 테스트 프레임워크에 의해 제공되는 실행 프레임워크는 모든 시스템 테스트 케이스 또는 다양한 서브셋을 다른 기능과 [34]함께 자동으로 실행할 수 있도록 합니다.

TAP 결과

테스트 프레임워크는 1987년에 작성된 언어에 구애받지 않는 Test Anything Protocol의 단위 테스트 출력을 받아들일 수 있습니다.

가짜, 모크 및 통합 테스트

유닛 테스트는 각각 1개의 코드 유닛을 테스트하기 때문에 이 이름이 붙습니다.복잡한 모듈에는 1,000개의 유닛테스트가 있고, 단순한 모듈에는 10개밖에 없습니다.TDD에 사용되는 유닛테스트는 네트워크 접속은 말할 것도 없고 프로그램 내의 프로세스 경계를 넘지 않도록 합니다.이렇게 하면 테스트 실행 속도가 느려지고 개발자가 전체 스위트를 실행하지 못하게 되는 지연이 발생합니다.외부 모듈 또는 데이터에 대한 의존성을 도입하면 유닛 테스트도 통합 테스트로 바뀝니다.서로 관련된 모듈 체인으로 1개의 모듈이 잘못 동작할 경우 장애의 원인을 찾을 수 있는 위치가 명확하지 않습니다.

개발 중인 코드가 데이터베이스, 웹 서비스 또는 기타 외부 프로세스 또는 서비스에 의존하고 있는 경우 유닛 테스트 가능한 분리를 시행하는 것도 모듈러형,[35] 테스트 가능 및 재사용 가능한 코드를 설계할 수 있는 기회이자 원동력이 됩니다.다음 두 가지 단계가 필요합니다.

  1. 최종 설계에서 외부 액세스가 필요할 때마다 사용 가능한 액세스를 설명하는 인터페이스를 정의해야 합니다.TDD에 관계없이 이 방법을 사용하는 이점에 대한 자세한 내용은 의존성 반전 원칙을 참조하십시오.
  2. 인터페이스는 두 가지 방법으로 구현해야 합니다.하나는 실제로 외부 프로세스에 액세스하고 다른 하나는 가짜 또는 모의 프로세스입니다.가짜 오브젝트는 "Person object saved" 등의 메시지를 트레이스 로그에 추가하면 됩니다.이것에 대해 테스트 어설션을 실행하여 올바른 동작을 확인할 수 있습니다.모의 객체는 이름 및 기타 데이터가 예상과 다르게 테스트에 실패할 수 있는 테스트 어설션을 포함하고 있다는 점에서 다릅니다.

데이터 저장소 또는 사용자로부터 데이터를 반환하는 가짜 및 모의 객체 메서드는 테스트가 신뢰할 수 있는 동일한 실제 데이터를 항상 반환함으로써 테스트 프로세스에 도움이 됩니다.또한 오류 처리 루틴을 개발하고 안정적으로 테스트할 수 있도록 미리 정의된 결함 모드로 설정할 수 있습니다.장애 모드에서는 메서드가 무효, 불완전 또는 늘 응답을 반환하거나 예외를 발생시킬 수 있습니다.TDD에서는 데이터 스토어 이외의 가짜 서비스도 도움이 될 수 있습니다.가짜 암호화 서비스는 전달된 데이터를 암호화하지 않을 수 있습니다.가짜 난수 서비스는 항상 1을 반환할 수 있습니다.가짜 또는 모의 구현은 의존성 주입의 예입니다.

테스트 더블은 UUT가 의존하는 시스템 기능(일반적으로 클래스 또는 함수)을 대체하는 테스트 고유의 기능입니다.시스템에 테스트 더블을 도입할 수 있는 것은 링크와 실행의 2가지입니다.링크 시간 대체는 테스트 더블이 로드 모듈로 컴파일되어 테스트를 검증하기 위해 실행되는 것입니다.이 접근법은 일반적으로 컴파일을 위해 하드웨어 레벨코드의 2배가 필요한 타깃 환경 이외의 환경에서 실행할 때 사용됩니다.링커 대체의 대안은 실제 기능이 테스트 케이스 실행 중에 대체되는 런타임 대체입니다.이 대체는 일반적으로 알려진 함수 포인터의 재할당 또는 객체 치환을 통해 이루어집니다.

테스트 복식은 여러 가지 유형과 복잡성이 있습니다.

  • 더미 – 더미는 테스트 더블의 가장 단순한 형태입니다.필요한 경우 기본 반환값을 제공하여 링커 시간 치환을 용이하게 합니다.
  • Stub: 스터브는 더미에 단순화된 로직을 추가하여 다른 출력을 제공합니다.
  • 스파이 – 스파이는 파라미터와 상태 정보를 캡처하여 입수할 수 있도록 하고 테스트 코드에 접근자를 공개하여 개인 정보를 테스트함으로써 보다 고도의 상태 검증을 가능하게 합니다.
  • [Mock] : 테스트 고유의 동작을 검증하고 파라미터 값 확인 및 콜시퀀스를 수행하기 위해 개별 테스트 케이스에 의해 모크가 지정됩니다.
  • 시뮬레이터 – 시뮬레이터는 목표 능력의 높은 충실도를 제공하는 포괄적인 구성요소입니다(두 배).시뮬레이터는 일반적으로 상당한 추가 개발 [6]노력이 필요합니다.

이러한 의존성 주입의 결과로서 실제 데이터베이스 또는 기타 외부 액세스코드는 TDD 프로세스 자체에 의해 테스트되지 않습니다.이로 인해 발생할 수 있는 오류를 피하기 위해서는 위에서 설명한 인터페이스의 "실제" 구현으로 테스트 구동 코드를 인스턴스화하는 다른 테스트가 필요합니다.이것들은 통합 테스트이며 TDD 유닛 테스트와는 상당히 다릅니다.이들 중 수가 적기 때문에 유닛 테스트보다 적은 빈도로 실행해야 합니다.그럼에도 불구하고 동일한 테스트 프레임워크를 사용하여 구현할 수 있습니다.

영구 저장소 또는 데이터베이스를 변경하는 통합 테스트는 테스트에 실패하더라도 파일 또는 데이터베이스의 초기 및 최종 상태를 고려하여 항상 신중하게 설계해야 합니다.이것은, 많은 경우, 다음의 몇개의 테크닉의 편성을 사용해 실현됩니다.

  • TearDown많은 테스트 프레임워크에 필수적인 방법.
  • try...catch...finally 예외 처리 구조(사용 가능한 경우)
  • 트랜잭션이 쓰기, 읽기 및 일치하는 삭제 작업을 포함하는 데이터베이스 트랜잭션입니다.
  • 테스트를 실행하기 전에 데이터베이스의 "스냅샷"을 작성하고 각 테스트 실행 후에 스냅샷으로 롤백합니다.이는 Ant 또는 NAnt와 같은 프레임워크 또는 크루즈 컨트롤과 같은 연속 통합 시스템을 사용하여 자동화할 수 있다.
  • 테스트 후 청소가 아닌 테스트 전에 데이터베이스를 클린 상태로 초기화합니다.이는 청소로 인해 상세 진단을 수행하기 전에 데이터베이스의 최종 상태를 삭제하여 테스트 실패를 진단하기 어려울 수 있는 경우에 관련될 수 있습니다.

복잡한 시스템용 TDD

까다로운 대규모 시스템에서 TDD를 사용하려면 모듈러 아키텍처, 퍼블리싱된 인터페이스를 갖춘 명확한 컴포넌트 및 플랫폼 독립성을 극대화하는 규율된 시스템 계층화가 필요합니다.이와 같이 실적이 있는 프랙티스를 통해 테스트성이 향상되고 빌드 [6]및 테스트 자동화의 적용이 용이해집니다.

테스트성을 위한 설계

복잡한 시스템에서는 다양한 요건을 충족하는 아키텍처가 필요합니다.이러한 요건의 주요 서브셋에는 시스템의 완전하고 효과적인 테스트 지원이 포함됩니다.효과적인 모듈러 설계를 통해 효과적인 TDD에 필수적인 특성을 공유하는 컴포넌트가 생성됩니다.

  • 높은 응집력을 통해 각 유닛이 일련의 관련 기능을 제공하고 이러한 기능의 테스트를 보다 쉽게 유지할 수 있습니다.
  • Low Coupling을 사용하면 각 장치를 격리하여 효과적으로 테스트할 수 있습니다.
  • 퍼블리시된 인터페이스는 컴포넌트 접근을 제한하고 테스트용 컨택포인트로 기능하며 테스트 작성을 용이하게 하고 테스트와 생산 유닛 구성 간의 충실도를 최대한 높입니다.

효과적인 모듈러 아키텍처를 구축하기 위한 주요 기술은 시나리오 모델링입니다. 시나리오 모델링에서는 일련의 시퀀스 차트가 구성되며, 각 차트는 단일 시스템 수준 실행 시나리오에 초점을 맞춥니다.시나리오 모델은 특정 자극에 대응하여 구성요소 간의 상호작용 전략을 수립하기 위한 우수한 수단을 제공합니다.각 시나리오 모델은 컴포넌트가 제공해야 하는 서비스 또는 기능의 풍부한 요건으로서 기능하며 이들 컴포넌트와 서비스가 상호 작용하는 순서도 지정합니다.시나리오 모델링은 복잡한 [6]시스템에 대한 TDD 테스트 구축을 크게 촉진할 수 있습니다.

대규모 팀 테스트 관리

대형 시스템에서는 컴포넌트 품질의 저하의 영향이 상호작용의 복잡성에 의해 확대됩니다.이러한 확대에 의해, 대규모 프로젝트에서는 TDD의 메리트가 한층 더 빠르게 축적됩니다.그러나 전체 테스트 모집단의 복잡성은 그 자체로 문제가 되어 잠재적 이득을 잠식할 수 있다.간단한 것처럼 들리지만, 중요한 첫 단계는 테스트 코드도 중요한 소프트웨어이므로 프로덕션 코드와 동일하게 제작 및 유지 관리해야 한다는 것을 인식하는 것입니다.

복잡한 시스템 내에서 테스트 소프트웨어의 아키텍처를 작성하고 관리하는 것도 핵심 제품 아키텍처와 마찬가지로 중요합니다.테스트 드라이버는 UUT, 테스트 더블 및 유닛 테스트 [6]프레임워크와 상호 작용합니다.

회의.

제1회 TDD 회의는 2021년 [36]7월에 개최되었습니다.컨퍼런스는 유튜브[37] 녹음되었다.

「 」를 참조해 주세요.

레퍼런스

  1. ^ Kent Beck (May 11, 2012). "Why does Kent Beck refer to the "rediscovery" of test-driven development?". Retrieved December 1, 2014.
  2. ^ a b c Beck, Kent (2002-11-08). Test-Driven Development by Example. Vaseem: Addison Wesley. ISBN 978-0-321-14653-3.
  3. ^ Lee Copeland (December 2001). "Extreme Programming". Computerworld. Archived from the original on June 5, 2011. Retrieved January 11, 2011.
  4. ^ a b Newkirk, JW 및 AA Vorontsov.Microsoft의 테스트 주도의 개발.NET, Microsoft Press, 2004.
  5. ^ Features, M. Legacy Code를 통한 효과적인 작업, 프렌티스 홀, 2004
  6. ^ a b c d e f g "Effective TDD for Complex Embedded Systems Whitepaper" (PDF). Pathfinder Solutions. Archived from the original (PDF) on 2016-03-16.
  7. ^ "Agile Test Driven Development". Agile Sherpa. 2010-08-03. Archived from the original on 2012-07-23. Retrieved 2012-08-14.
  8. ^ Koskela, L. "테스트 기반: Java Developers용 TDD 및 Acceptance TDD", Manning Publications, 2007
  9. ^ a b Pathfinder 솔루션에 의한 YouTube의 복잡한 시스템용 TDD(Test-Driven Development) 소개
  10. ^ Erdogmus, Hakan; Morisio, Torchiano. "On the Effectiveness of Test-first Approach to Programming". Proceedings of the IEEE Transactions on Software Engineering, 31(1). January 2005. (NRC 47445). Archived from the original on 2014-12-22. Retrieved 2008-01-14. We found that test-first students on average wrote more tests and, in turn, students who wrote more tests tended to be more productive.
  11. ^ Proffitt, Jacob. "TDD Proven Effective! Or is it?". Archived from the original on 2008-02-06. Retrieved 2008-02-21. So TDD's relationship to quality is problematic at best. Its relationship to productivity is more interesting. I hope there's a follow-up study because the productivity numbers simply don't add up very well to me. There is an undeniable correlation between productivity and the number of tests, but that correlation is actually stronger in the non-TDD group (which had a single outlier compared to roughly half of the TDD group being outside the 95% band).
  12. ^ Llopis, Noel (20 February 2005). "Stepping Through the Looking Glass: Test-Driven Game Development (Part 1)". Games from Within. Retrieved 2007-11-01. Comparing [TDD] to the non-test-driven development approach, you're replacing all the mental checking and debugger stepping with code that verifies that your program does exactly what you intended it to do.
  13. ^ Mayr, Herwig (2005). Projekt Engineering Ingenieurmässige Softwareentwicklung in Projektgruppen (2., neu bearb. Aufl. ed.). München: Fachbuchverl. Leipzig im Carl-Hanser-Verl. p. 239. ISBN 978-3446400702.
  14. ^ Müller, Matthias M.; Padberg, Frank. "About the Return on Investment of Test-Driven Development" (PDF). Universität Karlsruhe, Germany: 6. S2CID 13905442. Archived from the original (PDF) on 2017-11-08. Retrieved 2012-06-14. {{cite journal}}:Cite 저널 요구 사항 journal=(도움말)
  15. ^ a b c Madeyski, L. "시험 주도 개발 - 신속한 실행 방법의 경험적 평가", Springer, 2010, ISBN 978-3-642-04287-4, 페이지 1-245.DOI: 978-3-642-04288-1
  16. ^ Test-First 프로그래밍이 단위 테스트의 분기 범위 및 변환 점수 표시기에 미치는 영향: L. Madeyski 정보기술 52 (2)의 실험: 169-184 (2010)
  17. ^ L. Madeyski PROFES 2007의 유닛 테스트의 완전성장애 검출 효율에 대한 페어 프로그래밍의 영향: 207-221
  18. ^ 페어 프로그래밍이 장치 테스트 스위트의 완전성고장 감지 효율성에 미치는 영향. L. Madeyski 소프트웨어 프로세스: 개선 및 프랙티스 13(3): 281-295(2008)
  19. ^ M. 판추르와 M.시글라리치, "테스트 주도 개발이 생산성, 코드 및 테스트에 미치는 영향:통제된 실험", 정보 및 소프트웨어 기술, 2011, vol. 53, No. 6, 페이지 557–573, DOI: 10.1016/j.infsof.2011.02.002
  20. ^ D. Fucci, H. Erdogmus, B.Turhan, M. Oivo 및 N. Juristo, "테스트 주도의 개발 프로세스의 분석: 테스트 우선과 테스트 라스트 중 어느 것이 정말로 중요한가?", IEEE Transactions on Software Engineering, 2017, vol. 43, No., pp.597–614, DOI: 10.1109/168SE.
  21. ^ A. Tosun, O.디에스테 투비오, D.Fuci, S. Vegas, B.투르한, H. 에르도그머스, A.산토스, M. 오이보, KToro, J. Jarvinen 및 N. Juristo, "시험 주도 개발이 외부 품질과 생산성에 미치는 영향에 대한 업계 실험", 경험적 소프트웨어 엔지니어링, 2016, vol. 22, 페이지 1~43, DOI: 10.1007/s10664-016-9490
  22. ^ B. 파피스, K. 그로호스키, K. 수브즈다, K.Sijko, "실제 산업 프로젝트에 종사하는 인턴과 함께 테스트 주도의 개발에 대한 실험적 평가", IEEE Transactions on Software Engineering, 2020, DOI: 10.1109/TSE.20.3027522
  23. ^ "Problems with TDD". Dalkescientific.com. 2009-12-29. Retrieved 2014-03-25.
  24. ^ Hunter, Andrew (2012-10-19). "Are Unit Tests Overused?". Simple-talk.com. Retrieved 2014-03-25.
  25. ^ Loughran, Steve (November 6, 2006). "Testing" (PDF). HP Laboratories. Retrieved 2009-08-12.
  26. ^ "Fragile Tests".
  27. ^ Leybourn, E. (2013) 신속한 변화를 위한 조직: 비즈니스 관리에 대한어프로치.런던:IT 거버넌스 퍼블리싱: 176-179.
  28. ^ Lean-Agile Acceptance Test-Driven Development: Better Software Through Collaboration. Boston: Addison Wesley Professional. 2011. ISBN 978-0321714084.
  29. ^ "BDD". Retrieved 2015-04-28.
  30. ^ Burton, Ross (2003-11-12). "Subverting Java Access Protection for Unit Testing". O'Reilly Media, Inc. Retrieved 2009-08-12.
  31. ^ van Rossum, Guido; Warsaw, Barry (5 July 2001). "PEP 8 -- Style Guide for Python Code". Python Software Foundation. Retrieved 6 May 2012.
  32. ^ Newkirk, James (7 June 2004). "Testing Private Methods/Member Variables - Should you or shouldn't you". Microsoft Corporation. Retrieved 2009-08-12.
  33. ^ Stall, Tim (1 Mar 2005). "How to Test Private and Protected methods in .NET". CodeProject. Retrieved 2009-08-12.
  34. ^ "Effective TDD for Complex, Embedded Systems Whitepaper". Pathfinder Solutions. Archived from the original on 2013-08-20. Retrieved 2012-11-27.
  35. ^ Fowler, Martin (1999). Refactoring - Improving the design of existing code. Boston: Addison Wesley Longman, Inc. ISBN 0-201-48567-2.
  36. ^ Bunardzic, Alex. "First International Test Driven Development (TDD) Conference". TDD Conference. Retrieved 2021-07-20.
  37. ^ First International TDD Conference - Saturday July 10, 2021, archived from the original on 2021-12-21, retrieved 2021-07-20

외부 링크