TDD에서 아기의 발자국은 어떻습니까?


37

오늘 우리는 TDD를 훈련하고 있었고 다음과 같은 오해를 발견했습니다.

이 작업은 입력 "1,2"에 대한 숫자의 합계를 3으로 반환하는 것입니다.

numbers = input.Split(',');
return int.Parse(numbers[0]) + int.Parse(numbers[1]); //task said we have two numbers and input is correct

그러나 다른 사람들은 다른 방법으로 그것을 선호했습니다. 먼저 입력 "1,2"에 대해 다음 코드를 추가했습니다.

if (input == "1,2")
   return 3;

그런 다음 입력 "4,5"에 대한 테스트를 하나 더 도입하고 구현을 변경했습니다.

if (input == "1,2")
   return 3;
else if (input == "4,5")
   return 9;

그 후 그들은 "좋아, 이제 패턴을 본다"고 말하고 내가 처음에 한 일을 구현했습니다.

두 번째 접근 방식이 TDD 정의에 더 적합하다고 생각하지만 ... 우리는 그것에 대해 너무 엄격해야합니까? 나에게 사소한 아기 단계를 건너 뛰고 아무것도 건너 뛰지 않을 것이라고 확신하는 경우 "트윈 스텝"으로 결합하는 것이 좋습니다. 내가 잘못?

최신 정보. 나는 그것이 첫 번째 테스트가 아니었다는 것을 박살 내서 실수를했다. 이미 몇 가지 테스트가 있었으므로 "return 3"은 실제로 요구 사항을 충족시키는 가장 간단한 코드는 아니 었습니다.


25
내 동료들이 너무 작아서 "Ooahhh dazso cuuuuuute"
Adel

6
@Adel : 거의 내 아침에 숨 막혀, 키보드 지금 전체 또는 침과 부스러기
이진 걱정하는

2
@Adel, 비 원어민에 관해서는, 나는이 유머를 이해하기가 다소 어렵지만 당신의 동료들은 다음과 같은 질문을 추측합니다 :)
SiberianGuy

8
@Idsa : 자녀의 첫 번째 단계를 보여줄 때 동료 응답을 바꿉니다. "Ooahhh dazso cuuuuuute"= "아 너무 귀여워요" Adel이 작성한 단위 테스트를 볼 때 단위 테스트 아기 단계를 보면 "아 너무 귀여워"라고 말합니다. 실제-아기 단계에 대한 반응 = 단위 테스트에 대한 반응 "아기 단계".
이진 걱정

3
@Binaryworrier 나는 당신에게 육아를 설명하기 위해 시간을내어 실제 포인트를 줄 수 있기를 바랍니다
Andrew T Finnell

답변:


31

테스트를 통과시키는 가장 간단한 코드를 작성하십시오.

내가 볼 수있는 한, 어느 쪽도 그렇게하지 않았습니다.

아기 단계 1.

테스트 : 입력 "1,2"에 대해 3 인 숫자의 합을 반환

테스트 실패 :

throw NotImplementedException();

시험 합격 :

return 3;

아기 단계 2.

테스트 : 입력 "1,2"의 경우 숫자의 합을 반환합니다.

테스트 : 입력 "4,5"의 경우 숫자의 합 (9)을 반환

두 번째 테스트는 실패하므로 통과하십시오.

numbers = input.Split(',');
return int.Parse(numbers[0]) + int.Parse(numbers[1]);

(if ... return 목록보다 간단합니다)

이 경우 분명히 명백한 구현을 주장 할 수 있지만, 아기 단계에서 엄격하게 수행하는 것에 대해 이야기하는 경우 올바른 단계, IMO입니다.

논쟁은 두 번째 테스트를 작성하지 않으면 나중에 약간의 불꽃이 와서 코드를 "리팩터링"하여 읽을 수 있다는 것입니다.

return input.Length; # Still satisfies the first test

그리고 두 단계를 모두 거치지 않고 두 번째 테스트를 빨간색으로 한 적이 없습니다 (테스트 자체가 의심 스럽다는 의미).


입력에 관해서. 길이 예제, 같은 성공을 거두면 두 가지 테스트 모두에서 포착되지 않는 미친 잘못된 구현을 상상할 수 있습니다.
SiberianGuy

@Idsa-그렇습니다. 실제로 테스트를 많이 작성할수록 구현이 더 화를냅니다. input.Length특히 메소드에 대한 입력이 어딘가에서 일부 파일의 측정이고 실수로 메소드를 호출 한 경우에는 그렇게 많이 가져 오지 않습니다 Size().
pdr

6
+1. TDD를 배우는 방법과 관련하여 이것이 올바른 방법입니다. 일단 배운 후에는 때로는 명백한 구현으로 직접 갈 수 있지만 TDD에 대한 느낌을 얻으려면 훨씬 좋습니다.
Carl Manaster

1
"테스트"자체에 관한 질문이 있습니다. "4,5"입력에 대한 테스트를 작성 하거나 원래 테스트를 수정 하시겠습니까?
mxmissile

1
@ mxmissile : 새로운 테스트를 작성합니다. 시간이 많이 걸리지 않으며 나중에 리팩토링을 수행 할 때 사용자를 보호하기 위해 두 배의 테스트가 필요합니다.
pdr

50

두 번째 방법은 바보 같은 마음입니다. 나는 작은 걸음을 내딛는 것의 가치를 보았지만, 그 작은 접합체 (아기라고도 할 수 없음) 걸음을 쓰는 것은 단지 소박하고 시간 낭비입니다. 특히 해결하려는 원래 문제가 이미 자체적으로 너무 작은 경우.

나는 그것이 훈련임을 알고 원리를 보여주는 것에 관한 것이지만, 그러한 예는 TDD가 좋은 것보다 더 나쁘다고 생각합니다. 베이비 스텝의 가치를 보여주고 싶다면 적어도 가치가있는 문제를 사용하십시오.


+1하고 새 단어를 찾아 보게 해주셔서 감사합니다. (asinine)
Marjan Venema

12
엄청나게 바보라고 불러 +1. TDD는 모두 훌륭하지만 현대적인 프로그래밍 기술과 마찬가지로 길을 잃지 않도록주의해야합니다.
stijn

2
"특히 해결하려는 원래 문제가 이미 자체적으로 매우 작은 경우" -입력이 두 개의 정수로 합쳐지면 이것에 동의하지만 "문자열을 쪼개고 결과에서 두 개의 정수를 파싱하여 추가"할 때 확신하지 못합니다. 실제 세계의 대부분의 방법은 그보다 훨씬 복잡하지 않습니다. 실제로, 두 개의 쉼표, 정수가 아닌 값 등을 찾는 것과 같은 최첨단 사례를 다루기 위해 더 많은 테스트가 필요합니다.
pdr

4
@ pdr : 가장자리 케이스를 처리하기 위해 더 많은 테스트가 필요하다는 것에 동의합니다. 그것들을 작성하고 그것을 구현하기 위해 구현을 변경해야한다는 것을 알았을 때 반드시 그렇게하십시오. 필자는 그것을 작성하고 거기에서 나가는 대신 첫 번째 행복한 경로 인 "명백한 구현"으로 zygote 단계를 취하는 데 문제가 있다고 생각합니다. 나는 내 몸의 모든 섬유가 다음 순간에 사라질 것이라는 if 문을 작성하는 것의 가치를 보지 못합니다.
Christophe Vanfleteren

1
@ChristopheVanfleteren : Beck이 명백한 구현을 설명 할 때, 그는 두 개의 정수의 합계를 예로 사용 하지만 쌍 / 리뷰어가 시험 통과. 이 시나리오에 대해 하나의 테스트 만 작성하는 경우 절대적인 확실성입니다. 또한이 문제를 해결하는 세 가지 "명백한"방법을 생각할 수 있습니다. 분할 및 추가, 쉼표를 +로 바꾸고 평가하거나 정규 표현식을 사용하십시오. TDD의 요점은 올바른 선택을하도록하는 것입니다.
pdr

19

켄트 벡 (Kent Beck)은 그의 책 'Test Driven Development : By By Example'에서이를 다루고 있습니다.

귀하의 예는 ' 명확한 구현 '을 나타냅니다 -합계 두 개의 입력 값을 반환하려고합니다. 이는 매우 기본적인 알고리즘입니다. 당신의 반례는 '만약 당신이 그것을 만들 때까지 가짜'(매우 간단한 경우에도)에 빠지게됩니다.

명백한 구현은 이것보다 훨씬 더 복잡 할 수 있지만 기본적으로 메소드의 스펙이 매우 타이트한 경우 시작됩니다. 예를 들어 클래스 인코딩의 URL 인코딩 버전을 리턴하십시오. 위조 인코딩.

반면 데이터베이스 연결 루틴은 약간 더 많은 생각과 테스트가 필요하므로 구현이 명확하지 않습니다 (다른 프로젝트에서 이미 여러 번 작성 했더라도).

책에서 :

실제로 TDD를 사용할 때 일반적 으로이 두 가지 구현 모드 사이를 이동합니다. 모든 것이 원활하게 진행되고 입력해야 할 것을 알면 명백한 구현 후 명백한 구현을 수행합니다 (매번 테스트를 실행하여 나에게 분명한 것이 무엇인지 확인합니다) 여전히 컴퓨터에 분명합니다). 예기치 않은 빨간색 막대가 표시되면 백업을 수행하고 가짜 구현으로 전환 한 다음 올바른 코드로 리팩터링합니다. 자신감이 돌아 오면 명백한 구현으로 돌아갑니다.


18

나는 이것이 법의 서한을 따르는 것으로 본다. 그러나 그 정신은 아니다.

아기 발자국은 다음과 같아야합니다.

가능한 한 단순하지만 단순하지는 않습니다.

또한, 방법의 동사는 sum

if (input == "1,2")
   return 3;

합계가 아니며 특정 입력에 대한 테스트입니다.


4

나에게 몇 가지 사소한 구현 단계를 하나의 사소한 사소한 단계로 결합하는 것이 좋습니다. 나는 항상 그렇게합니다. 나는 편지에 매번 TDD를 따르는 것에 대해 종교적이어야한다고 생각하지 않습니다.

OTOH 이것은 위의 예와 같이 아주 사소한 단계에만 적용됩니다. 한 번에 완전히 기억할 수 없거나 결과에 대해 110 % 확신 할 수없는 더 복잡한 것은 한 번에 한 단계 씩 진행하는 것을 선호합니다.


1

TDD의 길을 처음 시작할 때이 질문에서 알 수 있듯이 단계의 크기는 혼란스러운 문제가 될 수 있습니다. 테스트 구동 응용 프로그램을 처음 시작할 때 자주 묻는 질문은 다음과 같습니다. 작성중인 테스트가 애플리케이션 개발을 촉진하는 데 도움이됩니까? 이것은 사소한 것처럼 보일 수 있으며 일부와 관련이 없지만 잠시 나와 함께 있습니다.

이제 응용 프로그램을 작성하려고 할 때 일반적으로 테스트를 시작합니다. 시험이 얼마나 많은 단계를 수행 하는가는 내가 무엇을 하려는지에 대한 나의 이해와 크게 관련이 있습니다. 내가 머리에 클래스의 행동을 거의 가지고 있다고 생각한다면 단계는 큰 단계가 될 것입니다. 내가 해결하려고하는 문제가 훨씬 명확하지 않으면 단계는 단순히 X라는 메서드가 있고 Y를 반환한다는 것을 알 수 있습니다.이 시점에서 메서드에는 매개 변수가 없으며 메소드 이름과 리턴 유형이 변경 될 가능성이 있습니다. 두 경우 모두 테스트로 인해 개발이 진행되고 있습니다. 그들은 내 응용 프로그램에 대해 나에게 이야기하고 있습니다.

내 머릿속에있는이 수업이 실제로 작동합니까?

또는

내가 어떻게이 일을 할까?

요점은 눈 깜짝 할 사이에 큰 단계와 작은 단계 사이를 전환 할 수 있다는 것입니다. 예를 들어 큰 단계가 작동하지 않고 그 주위에 확실한 방법이 없으면 작은 단계로 전환합니다. 그래도 작동하지 않으면 더 작은 단계로 전환합니다. 그런 다음 실제로 막히면 삼각 측량과 같은 다른 기술이 있습니다.

나처럼 당신이 개발자이고 테스터가 아니라면 TDD를 사용하는 요점은 테스트를 작성하는 것이 아니라 코드를 작성하는 것입니다. 작은 테스트를 작성해도 아무런 이점이없는 경우에는 작성하지 않아도됩니다.

TDD와 함께 훈련을 즐기시기 바랍니다. IMHO 더 많은 사람들이 감염된 경우 세계가 더 나은 곳이 될 것입니다 :)


1

단위 테스트에 대한 입문서에서 나는 똑같은 접근법 (정말로 아주 작은 단계)을 읽었으며, 내가 좋아하는 것에 대해 "작은 것이 얼마나 작아야하는지"라는 질문에 대한 답변으로

단계가 작동한다고 확신합니다. 원한다면 정말 큰 걸음을 내딛을 수 있습니다. 그러나 한동안 시도해 보면 당연하다고 생각하는 장소에 대해 많은 자신감을 갖게 될 것입니다. 따라서 테스트를 통해 사실 기반 신뢰를 구축 할 수 있습니다.

그래서, 아마도 당신의 동료는 조금 부끄러 울 것입니다 :)


1

테스트가 성공하는 한 메소드의 구현이 관련이 없다는 것이 요점은 아닙니까? 두 번째 예에서는 테스트 확장이 더 빨리 실패하지만 두 경우 모두 실패 할 수 있습니다.


1
시간 낭비를 전혀 신경 쓰지 않는다면 관련이 없습니다
SiberianGuy

1

나는 사람들이 가장 간단한 구현이 아니라고 말하는 것에 동의합니다.

방법론이 매우 엄격한 이유는 가능한 많은 관련 테스트를 작성해야한다는 것입니다. 이 때문에 하나 개의 테스트 케이스에 대한 상수 값을 반환하고 그것에게 패스를 호출하면 괜찮 강제로 돌아가서 당신이 정말로 당신의 프로그램에서 말도 안되는 이외의 것을 얻기 위해 원하는 것을 지정할 수 있습니다. 이러한 사소한 사례를 사용하는 것은 몇 가지 측면에서 발을 딛고 있지만 원칙은 '너무 많이'하려고 할 때 실수가 사양의 격차에 빠지고 가능한 가장 간단한 구현으로 요구 사항을 렌더링한다는 것이 실제로 원하는 행동의 각 고유 한 측면에 대해 테스트를 작성해야합니다.


"상수 값 반환"에 관한 업데이트를 추가했습니다
SiberianGuy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.