테스트 기반 개발을 수행하는 방법


15

응용 프로그램 개발 분야에서 2 년 이상 경험이 있습니다. 이 2 년 동안 개발에 대한 나의 접근 방식은 다음과 같습니다.

  1. 요구 사항 분석
  2. Identity Core 구성 요소 / 개체, 필수 기능, 동작, 프로세스 및 제약
  3. 클래스, 클래스 간 관계, 객체의 동작 및 상태에 대한 제약 조건 만들기
  4. 요구 사항에 따라 행동 제약 조건으로 기능 생성, 처리
  5. 수동 테스트 응용 프로그램
  6. 요구 사항 변경으로 구성 요소 / 기능이 수정되면 응용 프로그램을 수동으로 테스트하십시오.

최근에 TDD를 소개 받았으며 개발 된 코드가 존재하는 강력한 이유가 있고 많은 사후 배포 문제가 완화되어 개발을 수행하는 데 매우 좋은 방법이라고 생각합니다.

그러나 내 문제는 먼저 테스트를 만들 수 없다는 것입니다. 오히려 실제로 구성 요소를 작성하기 전에 구성 요소를 식별하고 테스트를 작성하는 것입니다. 내 질문은

  1. 내가 옳은거야? 내가 정확히 바꾸어야 할 것이 아니라면
  2. 작성한 시험이 충분한 지 확인할 수있는 방법이 있습니까?
  3. 1 + 1 = 2에 해당하는 매우 간단한 기능에 대한 테스트를 작성하는 것이 좋습니까?
  4. 기능을 변경하고 요구 사항이 변경되는지 테스트하는 것이 좋습니까?

2
"실제로 구성 요소를 작성하기 전에 구성 요소를 식별하고 구성 요소에 대한 테스트 만 작성하고 있습니다." 코딩 (TDD) 중에 개별 구성 요소의 세부 사항을 해결하고 그 과정에서 해결할 수있는 아키텍처 문제를 발견 할 수 있습니다. 그러나 사전 분석없이 코딩을 시작하지 않는 것이 좋습니다.
Giorgio

TDD 수행 하지 않고 자동화 된 단위 / 통합 테스트 수행 할 수도 있습니다 . 이 두 가지는 종종 혼동되지만 같은 것은 아닙니다.
Andres F.

답변:


19

내가 옳은거야? 내가 정확히 바꾸어야 할 것이 아니라면

그 짧은 설명만으로는 말하기가 어렵지만, 당신이 그것을 올바르게하고 있지 않다고 생각합니다 . 참고 : 나는 당신이하고있는 일이 효과가 없거나 어떤 식 으로든 나쁘다고 말하지는 않지만 TDD를하고 있지 않습니다. 중간 "D"는 "구동"을 의미하며, 테스트는 모든 것, 개발 프로세스, 코드, 디자인, 아키텍처, 모든 것을 주도 합니다.

시험은 무엇을 쓸 것인지, 언제 쓸 것인지, 다음에 쓸 것인지, 언제 멈추어야 할지를 알려줍니다. 디자인과 아키텍처를 알려줍니다. (디자인과 아키텍처는 코드에서 리팩토링을 통해 나온다.) TDD는 테스트에 관한 것이 아니다. 테스트를 먼저 작성하는 것조차 중요하지 않습니다. TDD는 테스트를 통해 사용자를 이끌어주는 것입니다. 먼저 테스트를 작성하는 것이 필요한 전제 조건입니다.

실제로 코드를 작성했는지, 아니면 완전하게 처리했는지는 중요하지 않습니다. 머리에 코드를 작성하고 해당 코드에 대한 테스트를 작성하는 것입니다. 그것은 TDD가 아닙니다.

그 습관을 버리는 것은 어렵다 . 정말 힘들어요 숙련 된 프로그래머에게는 특히 어려운 것 같습니다.

Keith Braithwaite는 TDD As If You Meant It 이라고하는 운동을 만들었습니다 . 그것은 엄격하게 따라야하고 TDD를보다 엄격하게 적용하도록 당신을 조종하도록 고안된 일련의 규칙 ( Bob Martin의 TDD의 세 가지 규칙을 기반으로 하지만 훨씬 더 엄격함)으로 구성됩니다. 페어 프로그래밍 (페어가 규칙을 위반하지 않도록 할 수 있도록) 및 강사와 함께 사용하는 것이 가장 좋습니다.

규칙은 다음과 같습니다.

  1. 솔루션의 방향을 가리키는 것으로 보이는 가장 작은 테스트를 정확히 하나만 작성하십시오.
  2. 실패를 참조하십시오. 컴파일 실패는 실패로 계산
  3. 테스트 방법에서 가능한 최소 구현 코드를 작성하여 (1)에서 테스트를 통과 하십시오 .
  4. 중복을 제거하기 위해 리팩터링하고 그렇지 않으면 디자인을 개선하는 데 필요합니다. 이 동작을 사용하는 것에 대해 엄격해야합니다.
    1. 새로운 방법이 필요합니다. 리팩토링 시간까지 기다렸다가 다음 중 하나를 수행하여 테스트하지 않은 새로운 방법을 작성하십시오.
      • 선호 : 테스트 클래스에서 새 메소드를 작성하려면 (3)에 따라 작성된 구현 코드에서 메소드 추출을 수행하십시오.
      • 필요한 경우 : (3)에 따라 구현 코드를 기존 구현 방법으로 이동
    2. 새로운 클래스를 원합니다. 리팩토링 시간까지 기다린 후… 테스트 방법 이외의 클래스를 만들어 Move Method의 목적지를 제공합니다.
    3. Move Method를 수행하여 다른 방법으로 구현 클래스를 메소드로 채 웁니다.

일반적으로, 이것은 "실제로 생각해야 할 것을 머리에 상상 한 다음 테스트를 작성하여 그 디자인을 강요하고 이미 계획 한 디자인을 구현하기도합니다." 테스트 ".

의사 그룹이 pseudo-TDD를 사용하여 틱택 토 게임과 같은 것을 구현하면 일반적으로 Board3x3 배열의 Integers 클래스를 포함하는 매우 유사한 디자인으로 끝납니다 . 그리고 프로그래머의 적어도 일부는 실제로 "클래스가 필요하다는 것을 알기"또는 "테스트를 작성하기 위해 무언가를 필요로하기"때문에 테스트하지 않고이 클래스를 작성했을 것입니다. 그러나 같은 그룹에서 TDD를 적용하는 경우 강제로 TDD를 적용하는 경우가 많으며 종종 매우 다른 디자인으로 구성되어 종종 Board.

작성한 시험이 충분한 지 확인할 수있는 방법이 있습니까?

그들이 모든 비즈니스 요구 사항을 다룰 때. 테스트는 시스템 요구 사항의 인코딩입니다.

1 + 1 = 2에 해당하는 매우 간단한 기능에 대한 테스트를 작성하는 것이 좋습니까?

다시 한번 말하지만, 기능에 대한 테스트는 작성하지 않습니다. 테스트를위한 기능을 작성합니다. 테스트를 통과하는 기능이 사소한 것으로 판명되면 훌륭합니다! 시스템 요구 사항을 충족하기 위해 열심히 노력하지 않아도됩니다!

기능을 변경하고 요구 사항이 변경되는지 테스트하는 것이 좋습니까?

아뇨. 다른 길은 요 요구 사항이 변경되면 해당 요구 사항에 해당하는 테스트를 변경하고 실패한 다음 코드를 변경하여 통과시킵니다. 테스트는 항상 먼저 이루어집니다.

이 작업은 어렵습니다. 마감 시간이 다가오고 압력을 받고있을 때 생각할 필요가없는 시점에 도달하기 위해 일종의 "근육 기억"을 구축 하려면 수십, 수백 시간의 신중한 연습 이 필요합니다. 이 작업을 수행하는 것이 가장 빠르고 가장 자연스러운 방법이됩니다.


1
정말 명확한 답변입니다! 실용적인 관점에서 TDD를 연습 할 때 유연하고 강력한 테스트 프레임 워크가 매우 즐겁습니다. TDD와 무관하지만 테스트를 자동으로 실행하는 기능은 응용 프로그램을 디버깅하는 데 매우 중요합니다. TDD를 시작하려면 종료 상태와 프로그램의 출력을 예상 한 것과 비교하여 유스 케이스를 테스트 할 수 있기 때문에 비 대화식 프로그램 (UNIX 스타일)이 가장 쉬운 방법 일 것입니다. 이 접근법의 구체적인 예는 OCaml 용 가솔린 라이브러리 에서 찾을 수 있습니다 .
Michael Le Barbier Grünewald

4
"동일한 그룹이 TDD를 마치는 것처럼 강요 할 때, 그들은 종종 매우 다양한 디자인으로 끝날 것입니다. 종종 보드와 원격으로 유사한 것을 사용하지 않는 것이 좋습니다." . 그것이 좋은 일이라는 것이 전혀 명확하지 않으며, 구현이 새로운 누군가에게 매우 직관적이지 않은 것처럼 들리므로 유지 관리 관점에서 나쁠 수도 있습니다. 왜이 구현 다양성이 좋은지 또는 적어도 나쁘지 않은지 설명 할 수 있습니까?
Jim Clay

3
+1 TDD를 올바르게 설명한다는 점에서 정답입니다. 그러나 또한 TDD가 결함이있는 방법론 인 이유를 보여줍니다. 특히 알고리즘 문제에 직면 할 때 신중한 사고와 명시적인 설계가 필요합니다. 도메인 지식이없는 척하여 TDD가 규정 한대로 "맹인으로"TDD를하는 것은 불필요하게 어려움과 막 다른 골목을 초래합니다. 악명 높은 스도쿠 솔버 파괴를보십시오 (짧은 버전 : TDD는 도메인 지식을 이길 수 없습니다).
Andres F.

1
@AndresF .: 실제로, 링크 한 블로그 게시물은 TDD를 수행 할 때 Keith가했던 경험을 반영하는 것 같습니다 Board. ints (또는 이와 유사한 것)의 3x3 배열 . 반면에 TDDAIYMI를 수행하도록 강요하면 종종 도메인 지식을 캡처하기위한 미니 DSL을 만들게됩니다. 물론 일 화일뿐입니다. 통계적으로 과학적으로 건전한 연구는 좋지만, 이와 같은 연구에서 종종 그러 하듯이 너무 작거나 너무 비쌉니다.
Jörg W Mittag

@ JörgWMittag 내가 당신을 잘못 이해하면 저를 정정하십시오. 그러나 Ron Jeffries 가 "의사 -TDD "를하고 있다고 말하고 있습니까? 그것은 "진정한 스코틀랜드 인이 아닌"오류의 형태가 아닙니까? (나는 더 많은 과학적 연구가 필요하다는 것에 동의합니다. 내가 링크 한 블로그는 TDD 사용의 특정 사례의 화려한 실패에 대한 화려한 일화 일뿐입니다. 불행히도, TDD 복음 전도자는 나머지 사람들에게는 너무 시끄러운 것처럼 보입니다. 우리 중이 metholody와 그 주장 된 이점에 대한 실제 분석을해야합니다).
Andres F.

5

개발 접근 방식을 "하향식 전용"프로세스로 설명합니다. 더 높은 추상화 수준에서 시작하여 점점 더 세부 사항을 살펴 봅니다. TDD는 적어도 인기가있는 형태로 "하단"기술입니다. 그리고 대부분 "상향식 (top-down)"으로 일하는 사람에게는 "하향식 (bottom-up)"으로 일하는 것이 실제로 매우 유용하지 않을 수 있습니다.

그렇다면 어떻게 개발 프로세스에 더 많은 "TDD"를 가져올 수 있습니까? 먼저, 실제 개발 프로세스가 위에서 설명한 것처럼 항상 "하향식"인 것은 아닙니다. 2 단계 후에 다른 구성 요소와 독립적 인 일부 구성 요소를 식별했을 것입니다. 때로는 이러한 구성 요소를 먼저 구현하기로 결정합니다. 해당 구성 요소의 공개 API 세부 정보는 요구 사항 만 따르지 않으며 디자인 결정도 따릅니다. 이것은 TDD로 시작할 수있는 지점입니다. 컴포넌트를 어떻게 사용할 것인지, 실제로 API를 어떻게 사용할 것인지를 상상해보십시오. 테스트 형태로 이러한 API 사용법을 코딩하기 시작하면 TDD로 시작한 것입니다.

둘째, 존재하지 않는 다른 구성 요소에 먼저 의존하는 구성 요소부터 시작하여 더 많은 "하향식"을 코딩 할 때에도 TDD를 수행 할 수 있습니다. 당신이 배워야 할 것은 먼저 이러한 다른 의존성을 "모방"하는 방법입니다. 그러면 하위 수준 구성 요소로 이동하기 전에 고급 구성 요소를 만들고 테스트 할 수 있습니다. 하향식 방식으로 TDD를 수행하는 방법에 대한 자세한 예 는 Ralf Westphal의이 블로그 게시물 에서 찾을 수 있습니다 .


3

내가 옳은거야? 내가 정확히 바꾸어야 할 것이 아니라면

당신은 잘하고 있습니다.

작성한 시험이 충분한 지 확인할 수있는 방법이 있습니까?

예, 테스트 / 코드 적용 범위 도구를 사용하십시오 . Martin Fowler는 테스트 범위에 대한 좋은 조언 을 제공합니다 .

1 + 1 = 2에 해당하는 매우 간단한 기능에 대한 테스트를 작성하는 것이 좋습니까?

일반적으로 일부 입력에서 일부 결과를 산출 할 것으로 예상되는 모든 기능, 방법, 구성 요소 등은 단위 테스트에 적합합니다. 그러나 (엔지니어링) 생활에서 대부분의 것들과 마찬가지로, 절충점을 고려해야합니다. 단위 테스트를 작성하여 노력이 상쇄되어 장기적으로보다 안정적인 코드 기반이 만들어 집니까? 일반적으로 중요 / 핵심 기능에 대한 테스트 코드를 먼저 작성하도록 선택하십시오. 나중에 테스트되지 않은 일부 코드와 관련된 버그가 발견되면 테스트를 더 추가하십시오.

기능을 변경하고 요구 사항이 변경되는지 테스트하는 것이 좋습니까?

자동화 된 테스트를 수행하는 것이 좋은 점은 변경 사항이 이전 어설 션을 위반하는지 즉시 확인할 수 있다는 것입니다. 요구 사항 변경으로 인해 예상되는 경우 테스트 코드를 변경해도됩니다 (실제로 순수 TDD에서는 요구 사항에 따라 먼저 테스트를 변경 한 다음 새로운 요구 사항에 맞을 때까지 코드를 채택합니다).


코드 범위는 매우 신뢰할만한 측정 방법이 아닐 수 있습니다. 적용 범위의 %를 적용하면 일반적으로 많은 불필요한 테스트 (예 : 거의 모든 값을 추가하지 않는 테스트를위한 테스트 인 모든 매개 변수 null 검사에 대한 테스트 등) 및 테스트 시간이 거의 걸리지 않은 개발 시간 낭비 경로는 전혀 테스트되지 않을 수 있습니다.
Paul

3

작문 테스트는 소프트웨어 작성과 완전히 다른 접근법입니다. 테스트는 적절한 코드 기능 검증 (모두 통과)의 도구 일뿐만 아니라 디자인을 정의하는 힘입니다. 테스트 범위는 유용한 측정 기준이지만 자체 목표는 아닙니다. TDD의 목표는 코드 범위의 좋은 %에 도달하는 것이 아니라 코드를 작성하기 전에 코드의 테스트 가능성에 대해 생각하는 것입니다.

테스트 작성에 문제가있는 경우 TDD에 경험이있는 사람과 쌍으로 프로그래밍하는 세션을 수행하는 것이 좋습니다. 따라서 전체 접근 방식에 대해 "생각하는 방법"에 대한 경험을 얻을 수 있습니다.

또 다른 좋은 방법은 TDD를 사용하여 소프트웨어를 개발하는 온라인 비디오를 첫 번째 라인에서 보는 것입니다. 내가 한때 TDD를 소개 할 때 사용한 좋은 점 은 James Shore 의 Let 's Play TDD 였습니다 . 살펴보면, 등장하는 디자인이 어떻게 작동하는지, 테스트를 작성하는 동안 어떤 질문을해야하는지, 새로운 클래스와 메소드가 작성, 리팩토링 및 반복되는 방법을 설명합니다.

작성한 시험이 충분한 지 확인할 수있는 방법이 있습니까?

나는 이것이 잘못된 질문이라고 믿는다. TDD를 수행 할 때 소프트웨어를 작성하는 방법으로 TDD 및 새로운 디자인을 선택했습니다. 추가해야 할 새로운 기능이 항상 테스트로 시작되면 항상 테스트가 시작됩니다.

1 + 1 = 2에 해당하는 매우 간단한 기능에 대한 테스트를 작성하는 것이 좋습니까?

분명히 그것은 당신의 판단을 사용합니다. 메소드가 퍼블릭 API의 일부가 아닌 경우 매개 변수 null 검사에 대한 테스트를 작성하지 않는 것이 좋습니다. 그렇지 않으면 왜 Add (a, b) 메소드가 a + b를 반환하는지 확인하지 않습니까?

기능을 변경하고 요구 사항이 변경되는지 테스트하는 것이 좋습니까?

다시 말하지만 코드에 새로운 기능을 변경하거나 추가하면 요구 사항이 변경 될 때 새로운 테스트를 추가하든 기존 테스트를 변경하든 테스트를 시작합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.