TDD에서 "실제"코드는 언제 작성합니까?


147

교육 비디오에서 읽고 본 모든 예제에는 간단한 예제가 있습니다. 그러나 녹색이 된 후에 어떻게 "실제"코드를 작성하는지는 알 수 없습니다. 이것이 "리 팩터"부분입니까?

복잡한 방법으로 상당히 복잡한 객체를 가지고 있고 테스트를 통과하고 최소한으로 실패하면 최소한으로 작성합니다. 언제 돌아가서 실제 코드를 작성해야합니까? 그리고 다시 테스트하기 전에 얼마나 많은 실제 코드를 작성합니까? 나는 마지막 것이 더 직감이라고 추측합니다.

편집 : 모든 답변 감사합니다. 당신의 모든 대답이 엄청나게 도움이되었습니다. 내가 요청하거나 혼란스러워하는 것에 대해 다른 아이디어가있는 것 같습니다. 어쩌면있을 수도 있지만, 내가 요구하는 것은 학교 건축 신청서가 있다고합니다.

내 디자인에는 사용자 스토리 등으로 시작하려는 아키텍처가 있습니다. 여기에서 사용자 스토리를 작성하고 사용자 스토리를 테스트하는 테스트를 작성합니다. 사용자는 우리에게 사람들이 학교에 등록하고 등록비를 지불하도록합니다. 그래서 나는 그것을 실패하게 만드는 방법을 생각합니다. 그렇게하면 클래스 X (아마도 학생)에 대한 테스트 클래스를 설계하는데 실패합니다. 그런 다음 "학생"클래스를 만듭니다. 아마 "학교"몰라요.

그러나 어쨌든 TD 디자인 은 이야기를 통해 생각하도록 강요합니다. 테스트에 실패하면 왜 실패하는지 알지만 테스트를 통과 할 수 있다고 전제합니다. 디자인에 관한 것입니다.

나는 이것을 재귀에 대해 생각하는 것에 비유합니다. 재귀는 어려운 개념이 아닙니다. 실제로 머리에서 그것을 추적하는 것이 더 어려울 수 있지만 실제로 가장 어려운 부분은 재귀가 중단되는 시점을 멈추는 시점을 알고 있습니다 (물론 내 견해). 재귀가 먼저입니다. 그것은 불완전한 유추 일 뿐이며, 각 재귀 반복이 "통과"라고 가정합니다. 다시 한 번 의견입니다.

실제로 학교는보기 힘들다. 숫자 및 은행 원장은 간단한 산술을 사용할 수 있다는 의미에서 "쉬운"것입니다. 나는 a + b를보고 0을 반환합니다. 사람들의 시스템의 경우, 그것을 구현 하는 방법에 대해 더 열심히 생각 해야 합니다. 나는 실패, 합격, 리팩토링의 개념을 가지고 있습니다 (주로 연구 와이 질문으로 인해).

내가 알지 못하는 것은 내 의견으로는 경험이 부족하다는 것입니다. 새 학생 등록에 실패하는 방법을 모르겠습니다. 성을 입력하여 데이터베이스에 저장하는 사람을 실패시키는 방법을 모르겠습니다. 간단한 수학을 위해 +1을 만드는 방법을 알고 있지만 사람과 같은 엔터티를 사용하면 누군가 데이터베이스에 고유 한 ID 또는 다른 이름을 입력했을 때 데이터베이스 ID 또는 기타 다른 항목이 있는지 확인하기 위해 테스트하고 있는지 알 수 없습니다. 데이터베이스 또는 둘 다 또는 둘 다.

아니면 어쩌면 이것은 여전히 ​​혼란 스럽습니다.


193
TDD 후 사람들은 밤새 집으로 돌아갑니다.
hobbs

14
작성한 코드가 실제가 아니라고 생각하는 이유는 무엇입니까?
Goyo

2
@RubberDuck 다른 답변보다 더. 나는 곧 그것을 참조 할 것이라고 확신합니다. 그것은 여전히 ​​외국인이지만 나는 포기하지 않을 것입니다. 당신이 말한 것은 말이되었습니다. 나는 단지 내 상황이나 일반적인 비즈니스 응용 프로그램에서 이해하기 위해 노력하고 있습니다. 재고 시스템 등일 수있다. 나는 그것을 고려해야한다. 그래도 시간 내 주셔서 감사합니다. 감사.
johnny

1
대답은 이미 머리에 못을 박았지만 모든 테스트가 통과되고 새로운 테스트 / 기능이 필요하지 않는 한 코드가 완성되었다고 가정 할 수 있습니다.
ESR

3
이 질문에는 "복잡한 방법으로 상당히 복잡한 객체를 가지고있다"는 문제가있을 수 있다는 가정이 있습니다. TDD에서는 테스트를 먼저 작성하므로 매우 간단한 코드로 시작합니다. 이렇게하면 모듈 식이어야하는 테스트하기 쉬운 구조를 코딩해야합니다. 따라서 더 간단한 객체를 결합하여 복잡한 동작이 생성됩니다. 상당히 복잡한 객체 또는 메소드로
끝났다

답변:


243

복잡한 방법으로 상당히 복잡한 객체를 가지고 있고 테스트를 통과하고 최소한으로 실패하면 최소한으로 작성합니다. 언제 돌아가서 실제 코드를 작성해야합니까? 그리고 다시 테스트하기 전에 얼마나 많은 실제 코드를 작성합니까? 나는 마지막 것이 더 직감이라고 추측합니다.

"돌아가서" "실제 코드"를 쓰지 마십시오. 모두 실제 코드입니다. 당신이 할 것은 돌아가서 다른 테스트 추가입니다 강제로 당신이 변경 새로운 테스트 통과를 만들기 위해 코드를.

다시 테스트하기 전에 얼마나 많은 코드를 작성합니까? 없음 당신은 쓰기 제로 실패한 테스트없이 코드를 강제로 더 많은 코드를 작성 할 수 있습니다.

패턴을 확인 하시겠습니까?

도움이 되길 바라며 간단한 또 ​​다른 예를 살펴 보겠습니다.

Assert.Equal("1", FizzBuzz(1));

쉬운 피지.

public String FizzBuzz(int n) {
    return 1.ToString();
}

실제 코드라고 부르는 것이 아닙니다. 변경을 강제하는 테스트를 추가하겠습니다.

Assert.Equal("2", FizzBuzz(2));

우리는 바보 같은 것을 할 수는 if n == 1있지만 제정신 해결책으로 건너 뛸 것입니다.

public String FizzBuzz(int n) {
    return n.ToString();
}

시원한. 이것은 FizzBuzz 이외의 모든 숫자에 적용됩니다. 프로덕션 코드를 강제로 변경하는 다음 입력은 무엇입니까?

Assert.Equal("Fizz", FizzBuzz(3));

public String FizzBuzz(int n) {
    if (n == 3)
        return "Fizz";
    return n.ToString();
}

다시 한번. 아직 통과하지 못한 테스트를 작성하십시오.

Assert.Equal("Fizz", FizzBuzz(6));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    return n.ToString();
}

그리고 우리는 이제 3의 배수를 모두 다뤘습니다 (5의 배수도 아닙니다).

아직 "버즈"에 대한 테스트를 작성하지 않았으므로 작성해 보겠습니다.

Assert.Equal("Buzz", FizzBuzz(5));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n == 5)
        return "Buzz"
    return n.ToString();
}

그리고 다시, 우리는 처리해야 할 다른 사례가 있다는 것을 알고 있습니다.

Assert.Equal("Buzz", FizzBuzz(10));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n % 5 == 0)
        return "Buzz"
    return n.ToString();
}

이제 3의 배수도 아닌 5의 배수를 모두 처리 할 수 ​​있습니다.

지금까지는 리팩토링 단계를 무시하고 있었지만 중복되는 부분이 있습니다. 이제 정리해 봅시다.

private bool isDivisibleBy(int divisor, int input) {
    return (input % divisor == 0);
}

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
}

시원한. 이제 중복을 제거하고 잘 명명 된 함수를 만들었습니다. 코드를 변경하도록 강요 할 다음 테스트는 무엇입니까? 글쎄, 우리는 숫자를 3과 5로 나눌 수있는 경우를 피했습니다. 지금 적어 봅시다.

Assert.Equal("FizzBuzz", FizzBuzz(15));

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n) && isDivisibleBy(5, n))
        return "FizzBuzz";
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
}

테스트는 통과했지만 더 많은 중복이 있습니다. 옵션이 있지만 다시 작성하는 대신 리팩토링 할 수 있도록 "추출 로컬 변수"를 몇 번 적용하겠습니다.

public String FizzBuzz(int n) {

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
}

그리고 우리는 모든 합리적인 의견을 다루었지만, 불합리한 의견은 어떻습니까? 0 또는 음수를 전달하면 어떻게됩니까? 해당 테스트 사례를 작성하십시오.

public String FizzBuzz(int n) {

    if (n < 1)
        throw new InvalidArgException("n must be >= 1);

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
}

아직 "실제 코드"처럼 보이기 시작합니까? 더 중요한 것은 어떤 시점에서 "언리얼 코드"가 중단되고 "실제"로 전환 되었습니까? 그것은 숙고할만한 것입니다 ...

그래서, 나는 각 단계에서 통과하지 못할 것이라는 것을 알았지 만 많은 연습을 해본 테스트를 찾아 간단하게 수행 할 수있었습니다. 내가 일할 때 상황이 그렇게 간단하지는 않으며 어떤 테스트가 변경을 강제 할 것인지 항상 알 수는 없습니다. 때로는 테스트를 작성하고 이미 통과 한 것을보고 놀랄 것입니다! 시작하기 전에 "테스트 목록"을 작성하는 습관을들이는 것이 좋습니다. 이 테스트 목록에는 생각할 수있는 모든 "흥미로운"입력이 포함되어야합니다. 모두 사용하지 않을 수 있으며 진행하면서 사례를 추가 할 수도 있지만이 목록은 로드맵 역할을합니다. FizzBuzz에 대한 내 테스트 목록은 다음과 같습니다.

  • 부정
  • 제로
  • 하나
  • 다섯
  • 6 개 (3의 비소수 배수)
  • 아홉 (3 제곱)
  • 10 (5의 사소한 배수)
  • 15 (3과 5의 배수)
  • 30 (3과 5의 사소한 배수)

3
의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
maple_shaft

47
이 대답을 완전히 잘못 이해하지 않는 한 : "n == 1 인 경우 어리석은 짓을 할 수 있지만 제정신의 해결책으로 넘어갈 것입니다." -모든 것이 어리 석었습니다. 먼저 <spec>을 수행하는 함수를 원한다면 <spec>에 대한 테스트를 작성하고 <spec>에 실패한 버전을 작성하는 부분은 생략하십시오. <spec>에서 버그를 발견 한 경우 반드시 다음을 수행하십시오. 먼저 테스트를 작성하여 수정 전에 실행하고 수정 후에 테스트가 통과되는지 확인하십시오. 그러나 이러한 모든 중간 단계를 위조 할 필요는 없습니다.
GManNickG

16
이 답변과 TDD의 주요 결함을 지적하는 의견은 채팅으로 옮겨졌습니다. TDD 사용을 고려중인 경우 '채팅'을 읽으십시오. 불행히도 '품질'의견은 이제 미래의 학생들이 읽을 수있는 많은 대화 중에 숨겨져 있습니다.
user3791372

2
@GManNickG 요점은 올바른 양의 테스트를 얻는 것이라고 생각합니다. 미리 테스트를 작성하면 테스트해야 할 특수 사례를 놓치기가 쉬워 져 테스트에서 적절하게 다루지 않는 상황 또는 테스트에서 무의미하게 커버되는 상황과 같은 상황이 발생할 수 있습니다. 이 중간 단계없이 그렇게 할 수 있다면 좋습니다! 그래도 모든 사람이 그렇게 할 수있는 것은 아닙니다. 연습이 필요합니다.
hvd

1
그리고 리팩토링에 대한 켄트 벡 (Kent Beck)의 인용문은 다음과 같습니다. "이제 테스트가 실행되면,"( 실제로 만들다 "와 같이 summary ()의 구현을 실현할 수 있습니다. ") 그런 다음 상수를 변수로 변경합니다. 나는이 인용문이 그 질문과 잘 일치한다고 느꼈다.
Chris Wohlert

46

"실제"코드는 테스트를 통과하기 위해 작성하는 코드입니다. 정말 . 그렇게 간단합니다.

사람들이 테스트를 친환경으로 만들기 위해 최소한으로 작성하는 것에 대해 이야기 할 때, 이는 실제 코드가 YAGNI 원칙을 따라야 함을 의미합니다 .

리 팩터 단계의 아이디어는 요구 사항을 충족하는 것이 만족 스러우면 작성한 것을 정리하는 것입니다.

작성하는 테스트가 실제로 제품 요구 사항을 포함하는 한, 일단 통과하면 코드가 완성됩니다. 생각해보십시오. 모든 비즈니스 요구 사항에 테스트가 있고 해당 테스트가 모두 녹색이면 작성해야 할 것이 더 있습니까? (실제로 우리는 완벽한 테스트 범위를 갖지는 않지만 이론은 건전합니다.)


45
단위 테스트는 실제로 사소한 요구 사항에 대한 제품 요구 사항을 포함 할 수 없습니다. 기껏해야 그들은 입 / 출력 공간을 샘플링하며 아이디어는 전체 입 / 출력 공간으로 (정확하게) 일반화한다는 것입니다. 물론 switch모든 테스트를 통과하고 다른 입력에 실패하는 각 단위 테스트의 경우 코드가 클 수 있습니다 .
Derek Elkins

8
@DerekElkins TDD는 테스트 실패를 요구합니다. 단위 테스트에 실패하지 않았습니다.
Taemyr

6
@DerekElkins는 유닛 테스트를 작성하는 것이 아니라 가짜가 아닌 무언가를 만들려는 일반적인 가정이있는 이유입니다!
jonrsharpe

36
@jonrsharpe 그 논리에 의해 결코 간단한 구현을 쓰지 않을 것입니다. 예를 들어 RubberDuck의 답변 (단위 테스트 만 사용)의 FizzBuzz 예제에서 첫 번째 구현은 분명히 "그냥 가짜"입니다. 이 질문에 대한 나의 이해는 불완전한 코드 작성과 "실제 코드"라는 요구 사항을 실제로 구현할 것이라고 믿는 코드 사이의 이분법입니다. 내 "big switch"은 "테스트를 친환경으로 만들기 위해 최소한으로 쓰는 것"의 논리적 극단으로 의도되었습니다. 나는 OP의 질문을 다음과 같이 본다. TDD에서 이것을 크게 피하는 원칙은 어디 switch인가?
Derek Elkins

2
@GenericJon 그것은 내 경험에서 너무 낙관적입니다 :) 하나는, 생각없는 반복 작업을 즐기는 사람들이 있습니다. 그들은 "복잡한 의사 결정"보다는 거대한 스위치 진술로 더 행복 할 것입니다. 그리고 직업을 잃기 위해서는 기술에 대해 문의하는 사람이 필요하며 (실제로 회사의 기회 / 돈을 잃고 있다는 좋은 증거가 더 있습니다!) 이러한 많은 프로젝트에서 유지 관리를 인수 한 후 고객이 행복하고 지불하는 한 매우 순진한 코드가 수십 년 동안 지속되는 것이 쉽다는 것을 알 수 있습니다.
Luaan

14

짧은 대답은 "실제 코드"가 테스트를 통과시키는 코드라는 것입니다. 실제 코드 이외의 것으로 테스트 패스를 만들 수 있다면 더 많은 테스트를 추가하십시오!

TDD에 대한 많은 자습서가 단순하다는 데 동의합니다. 그것은 그들에 대해 작동합니다. 예를 들어, 3 + 8을 계산하는 방법에 대한 너무 간단한 테스트는 실제로 3 + 8을 계산하고 결과를 비교하는 것 외에는 선택의 여지가 없습니다. 따라서 코드 전체를 복제하는 것처럼 보이고 테스트는 무의미하고 오류가 발생하기 쉬운 추가 작업입니다.

테스트를 잘하면 응용 프로그램을 구성하는 방법과 코드를 작성하는 방법을 알 수 있습니다. 현명하고 유용한 테스트를 작성하는 데 문제가 있으면 디자인을 다시 생각해야합니다. 잘 설계된 시스템은 쉽게 테스트 할 수 있습니다. 즉 현명한 테스트는 생각하고 구현하기 쉽습니다.

먼저 테스트를 작성할 때 실패한 것을 확인한 다음 테스트를 통과시키는 코드를 작성하십시오. 이는 모든 코드에 해당하는 테스트가 있는지 확인하는 원칙입니다. 코딩 할 때이 규칙을 노예로 따르지 않습니다. 종종 사실 후에 테스트를 작성합니다. 그러나 먼저 테스트를 수행하면 정직하게 유지하는 데 도움이됩니다. 약간의 경험이 있으면 테스트를 먼저 작성하지 않아도 구석에 자신을 코딩 할 때 알 수 있습니다.


6
개인적으로 제가 작성한 테스트는 assertEqual(plus(3,8), 11)그렇지 않습니다 assertEqual(plus(3,8), my_test_implementation_of_addition(3,8)). 더 복잡한 경우에, 당신은 항상 결과가 올바른 증명하는 수단을 찾아 이외의 동적 테스트에서 올바른 결과를 계산하고 평등을 검사합니다.
Steve Jessop

따라서이 예제에서 실제로 수행하는 어리석은 방법의 plus(3,8)경우 3을 빼고 8을 빼고 결과를 0과 비교하여 올바른 결과를 반환 했음을 증명할 assertEqual(plus(3,8), 3+8)수 있습니다. 비트 터무니없는 것이지만 테스트중인 코드가 정수보다 복잡한 것을 구축하는 경우 결과를 취하고 각 부분의 정확성을 검사하는 것이 종종 올바른 접근법입니다. 또는 이와 비슷한for (i=0, j=10; i < 10; ++i, ++j) assertEqual(plus(i, 10), j)
Steve Jessop

... 큰 두려움을 피할 수 있기 때문에 테스트를 작성할 때 라이브 코드에서 만든 "10을 추가하는 방법"이라는 주제에 대해 동일한 실수를 범합니다. 따라서 테스트는 10을 추가 할 수있는 코드에 10을 추가하는 코드를 작성하지 않도록 조심스럽게 수행합니다 plus(). 물론 프로그래머 검증 된 초기 루프 값에 여전히 의존합니다.
Steve Jessop

4
사실 이후에 테스트를 작성하더라도 테스트 실패를 보는 것이 좋습니다. 코드에서 어떤 작업을 수행하든 결정적으로 중요한 부분을 찾은 다음 약간 조정 (예 : +를-로 바꾸거나 다른 작업으로 변경)하고 테스트를 실행하고 실패한 것을 확인하고 변경 사항을 취소하고 통과했는지 확인하십시오. 여러 번이 작업을 수행 한 결과 테스트가 실제로 실패하지 않아서 쓸모없는 것보다 더 나빠졌습니다. 테스트하지 않을뿐만 아니라 테스트되고 있다는 잘못된 확신을 심어줍니다!
Warbo

6

때때로 TDD에 대한 일부 예가 오도 될 수 있습니다. 다른 사람들이 이전에 지적했듯이 테스트를 통과시키기 위해 작성한 코드는 실제 코드입니다.

그러나 실제 코드가 마술처럼 보이지 않는다고 생각하지 마십시오. 달성하고자하는 것을 더 잘 이해해야하며, 가장 쉬운 경우와 코너 경우에서 시작하여 그에 따라 테스트를 선택해야합니다.

예를 들어, 어휘 분석기를 작성해야하는 경우 빈 문자열로 시작한 다음 여러 공백, 숫자, 공백으로 둘러싸인 숫자, 잘못된 숫자 등으로 시작합니다. 이러한 작은 변환으로 인해 올바른 알고리즘이지만 실제 코드를 완성하기 위해 가장 쉬운 경우에서 엄청나게 복잡한 경우로 넘어 가지 않습니다.

밥 마틴은 여기에 완벽하게 설명합니다 .


5

리 팩터 부분은 피곤하고 집에 가고 싶을 때 깨끗해집니다.

기능을 추가하려고 할 때 리 팩터 부분은 다음 테스트 전에 변경하는 부분입니다. 새로운 기능을위한 공간을 만들기 위해 코드를 리팩터링합니다. 새로운 기능이 무엇인지 때이 작업을 수행 합니다. 상상할 때가 아닙니다.

클래스 를 만들기 전에 (테스트를 추가 한 후) "Hi Mom"을 인쇄하는 기능을 추가 하기 GreetImpl위해 이름 을 바꾸는 것만 큼 간단 합니다.GreetWorldGreetMom


1

그러나 실제 코드는 TDD 단계의 리팩터링 단계에 나타납니다. 즉, 최종 릴리스에 포함되어야하는 코드입니다.

테스트는 변경할 때마다 실행되어야합니다.

TDD 수명주기의 좌우명은 다음과 같습니다. 적색 녹색 반사기

RED : 테스트 작성

초록색 : 중복 코드, 불명확하게 이름이 지정된 변수 핵 (hack) 등 가능한 빨리 테스트를 통과하는 기능 코드를 얻기 위해 정직하게 시도하십시오.

REFACTOR : 코드를 정리하고 변수 이름을 올바르게 지정하십시오. 코드를 말리 십시오.


6
"녹색"단계에 대해 무엇을 말하는지 알고 있지만 테스트를 통과하기위한 결선 리턴 값이 적절할 수 있음을 나타냅니다. 내 경험상 "녹색"은 요구 사항을 충족시키기 위해 작업 코드를 작성하려는 정직한 시도 여야합니다. 완벽하지는 않지만 개발자가 첫 번째 단계에서 관리 할 수있는 것처럼 완벽하고 "배송 가능"해야합니다. 리팩토링은 아마도 더 많은 개발을 마친 후 얼마 후에 가장 잘 수행 될 수 있으며 첫 번째 패스의 문제가 더 분명 해지고 DRY에 대한 기회가 나타납니다.
mcottle

2
@mcottle : 코드베이스에서 get-only 저장소의 구현이 하드 코딩 된 값이 될 수있는 방법에 놀랄 수 있습니다. :)
Bryan Boettcher

6
좋은 프로덕션 품질 코드를 입력 할 수있는 속도만큼 빠르게 크롤링 할 수있는 이유는 무엇입니까? :)
Kaz

1
@Kaz 이렇게하면 테스트되지 않은 동작 이 추가 될 위험이 있습니다 . 원하는 모든 행동을 테스트하는 유일한 방법은 그것이 얼마나 엉터리인지에 관계없이 가능한 간단한 변경 을 수행하는 것입니다. 때때로 다음의 리팩토링은 당신이 미리 생각하지 않은 새로운 접근법을 제공합니다 ...
Timothy Truckle

1
@TimothyTruckle 가장 간단한 변화를 찾는 데 50 분이 걸리지 만 가장 간단한 변화를 찾는 데 5 분이 걸리면 어떻게됩니까? 우리는 두 번째로 단순하게 진행합니까 아니면 가장 간단하게 검색합니까?
Kaz

1

TDD에서 "실제"코드는 언제 작성합니까?

빨간 어디 단계는 쓰기 코드를.

에서 리팩토링 단계의 기본 목표는 것입니다 삭제 코드를.

에서 빨간색 단계는 테스트를 통과하기 위해 아무것도 가능한 한 신속 하고 어떤 비용 . 좋은 코딩 방법이나 디자인 패턴에 대해 들어 본 내용을 완전히 무시하십시오. 친환경 테스트를하는 것이 중요합니다.

에서 리팩토링 단계 당신은 당신이 방금 만든 난장판을 청소하십시오. 이제 방금 변경 한 내용이 변환 우선 순위 목록 에서 가장 높은 변경 사항인지 확인하고 코드 복제가 있으면 디자인 패턴을 적용하여 가능성을 제거 할 수 있습니다.

마지막으로 당신은 이름을 변경 식별자에 의해 가독성을 개선하고 추출 매직 넘버 상수 및 / 또는 리터럴 문자열.


빨강 색 리 팩터가 아니라 빨강-녹색 리 팩터입니다. – Rob Kinyon

이것을 지적 해 주셔서 감사합니다.

실제 코드 를 작성하는 것은 녹색 단계입니다.

에서 빨간색 단계 당신은 쓰기 실행 가능한 사양을 ...


빨강 색 리 팩터가 아니라 빨강-녹색 리 팩터입니다. "빨간색"은 테스트 스위트를 녹색 (모든 테스트 통과)에서 빨간색 (하나의 테스트 실패)으로 가져갑니다. "녹색"은 테스트 스위트를 빨간색 (한 번의 테스트 실패)에서 녹색 (모든 테스트 통과)으로 부드럽게 가져 오는 곳입니다. "리 팩터"는 코드를 가져와 모든 테스트를 통과하면서 예쁘게 만드는 곳입니다.
Rob Kinyon

1

당신은 항상 Real Code를 작성 하고 있습니다.

각 단계에서 귀하는 귀하의 코드가 향후 귀하의 코드 발신자 (여러분이 될 수도 있고 아닐 수도 있음)에게 만족할 조건을 충족시키기 위해 코드를 작성하고 있습니다.

당신은 당신이 유용 (작성하지 않을 생각 실제 순간에 당신은 그것을 밖으로 리팩토링 수 있으므로) 코드.

코드 리팩터링 은 외부 동작을 변경하지 않고 기존 컴퓨터 코드를 재구성 (팩터링 변경)하는 프로세스입니다.

이것이 의미하는 바는 코드를 변경하더라도 코드가 만족 한 조건은 변경되지 않은 상태입니다. 그리고 수정 사항이 변경되었는지 확인하기 위해 코드가 이미 있는지 확인하기 위해 구현 한 검사 ( 테스트 ). 그래서 당신이 항상 쓴 코드는 다른 방식으로 존재합니다.

또 다른 이유는 그것이 실제 코드가 아니라고 생각할 수도 있습니다. 최종 프로그램이 이미 귀하에게 예측 될 수있는 예제를 수행하고 있기 때문입니다. 이것은 당신은에 대한 지식이 같이 매우 좋은 도메인 당신이 프로그래밍됩니다.
그러나 여러 번 프로그래머는에있는 도메인 입니다 , 알 수없는 그들. 그들은 최종 결과가 무엇인지 알지 못하고 TDD는 프로그램을 단계별로 작성 하는 기술 이며, 이 시스템의 작동 방식에 대한 지식을 문서화 하고 코드가 그렇게 작동하는지 확인합니다.

TDD에서 The Book (*)을 읽을 때 가장 중요한 기능은 TODO 목록이었습니다. TDD는 개발자가 한 번에 한 가지에 집중할 수 있도록 도와주는 기술이기도합니다. 그래서 이것은 또한 aboout 질문에 대한 답변입니다 많은 실제 코드를 작성하는 방법을 ? 한 번에 1 가지에 집중할 수있는 충분한 코드를 말하고 싶습니다.

(*) Kent Beck의 "테스트 주도 개발 : 예제 별"


2
Kent Beck의 "테스트 주도 개발 : 예제"
Robert Andrzejuk

1

테스트에 실패하도록 코드를 작성하지 않았습니다.

성공 여부를 정의하기 위해 테스트를 작성합니다. 아직 통과 할 코드를 작성하지 않았기 때문에 처음에는 모두 실패해야합니다.

초기에 실패한 테스트 작성에 대한 요점은 다음 두 가지를 수행하는 것입니다.

  1. 모든 케이스-모든 명목 케이스, 모든 에지 케이스 등을 포함합니다.
  2. 테스트를 확인하십시오. 당신은 그들이 통과를 본 적이 있다면, 그들이 실패했을 때 그들이 확실하게 실패를보고 할 것이라고 어떻게 확신 할 수 있습니까?

red-green-refactor의 요점은 올바른 테스트를 먼저 작성하면 테스트를 통과하기 위해 작성한 코드가 올바른지 알 수 있다는 확신을 갖게되며 테스트를 마치면 곧 알려줄 것이라는 확신을 가지고 리팩토링 할 수 있다는 것입니다 무언가가 깨져서 즉시 돌아가서 고칠 수 있습니다.

내 경험 (C # / .NET)에서 순수한 테스트 우선은 아직 달성 할 수없는 이상적인 방법입니다. 아직 존재하지 않는 메소드에 대한 호출을 컴파일 할 수 없기 때문입니다. 따라서 "먼저 테스트"는 실제로 인터페이스를 코딩하고 구현을 스텁하는 것입니다. 그런 다음 스텁이 올바르게 처리 될 때까지 스텁에 대해 테스트를 작성합니다 (처음에는 실패 함). 나는 단지 "실패한 코드"를 작성하지 않고 단지 스텁 (stub)으로부터 빌드한다.


0

단위 테스트와 통합 테스트가 혼동 될 수 있습니다. 수락 테스트도있을 수 있지만 프로세스에 따라 다릅니다.

작은 "단위"를 모두 테스트 한 후에는 모두 조립 또는 "통합 된"단위를 테스트합니다. 일반적으로 전체 프로그램 또는 라이브러리입니다.

내가 작성한 코드에서 데이터를 읽고 라이브러리에 공급하는 다양한 테스트 프로그램으로 라이브러리를 테스트 한 다음 결과를 확인하십시오. 그런 다음 스레드로 수행합니다. 그런 다음 중간에 스레드와 fork ()를 사용하여 수행합니다. 그런 다음 2 초 후에 실행하고 -9를 죽인 다음 시작하고 복구 모드를 확인합니다. 나는 그것을 퍼지한다. 나는 온갖 방법으로 고문합니다.

이 모든 것이 ALSO 테스트이지만 결과에 대한 빨간색 / 녹색 디스플레이는 없습니다. 성공했거나 수천 줄의 오류 코드를 파헤쳐 서 이유를 찾습니다.

"실제 코드"를 테스트하는 곳입니다.

그리고 나는 이것을 생각했지만, 단위 테스트 작성을 언제 해야할지 모를 수도 있습니다. 테스트에서 지정한 모든 작업을 수행하면 단위 테스트 작성이 완료됩니다. 때로는 모든 오류 처리 및 엣지 사례 중에서 그 사실을 추적하지 못할 수 있으므로 사양을 바로 통과하는 행복한 경로 테스트의 멋진 테스트 그룹을 만들 수 있습니다.


(그것의 = 소유 성, 그것은 = "그 것이다"또는 "그것이있다". 그것의 사용법과 그것의 예를 보라 .)
Peter Mortensen

-6

"TDD에"실제 "코드를 언제 작성합니까?"라는 질문의 제목에 대한 답은 '거의 적음'또는 '매우 느림'입니다.

당신은 학생처럼 들리므로 마치 학생에게 조언하는 것처럼 대답 할 것입니다.

많은 코딩 '이론'과 '기술'을 배우게됩니다. 고가의 학생 과정에 시간을 보내는 데는 좋지만 반 시간 안에 책을 읽을 수 없다는 이점은 거의 없습니다.

코더의 역할은 전적으로 코드를 생성하는 것입니다. 정말 잘 작동하는 코드. 그렇기 때문에 코더는 마음, 종이, 적절한 응용 프로그램 등으로 코드를 계획하고 코딩하기 전에 논리적으로 측면으로 생각하여 가능한 결함 / 구멍을 미리 해결하려고 계획합니다.

그러나 적절한 코드를 디자인하려면 응용 프로그램을 중단하는 방법을 알아야합니다. 예를 들어 Little Bobby Table (xkcd 327)에 대해 모른다면 데이터베이스를 사용하기 전에 입력 내용을 삭제하지 않았을 것이므로 해당 개념을 중심으로 데이터를 보호 할 수 없습니다.

TDD는 코드를 도입할수록 코드가 기하 급수적으로 어려워지고 한 번 생각했던 버그를 잊어 버리기 때문에 응용 프로그램을 코딩하기 전에 무엇이 잘못 될 수 있는지 테스트하여 코드의 버그를 최소화하도록 설계된 워크 플로입니다. 응용 프로그램을 완료했다고 생각되면 테스트와 붐을 실행하면 테스트에 버그가 생길 수 있습니다.

TDD는 일부 사람들이 생각하는 것처럼 테스트를 작성하고, 최소한의 코드로 통과 시키거나, 다른 테스트를 작성하거나, 최소한의 코드로 통과시키는 등의 방법이 아닙니다. 대신, 자신있게 코드를 작성하는 데 도움이됩니다. 테스트와 함께 작동하도록하는 지속적인 리팩토링 코드의 이상적인 이상은 바보이지만, 새로운 기능을 추가 할 때 기분이 좋아지고 코딩 방법을 배우고 있기 때문에 학생들에게 좋은 개념입니다.

이 함정을 무너 뜨리지 말고 코딩의 역할을 확인하십시오. 코더의 역할은 전적으로 코드를 생성하는 것입니다. 정말 잘 작동하는 코드. 이제 여러분은 전문 코더로서 24 시간 내내있을 것이라는 점을 기억하십시오. 클라이언트는 10 만 개의 주장을 쓰거나 0을 쓰더라도 신경 쓰지 않을 것입니다. 그들은 작동하는 코드 만 원합니다. 실제로는 정말 좋습니다.


3
나는 학생에게 가까이 있지 않지만 좋은 기술을 읽고 전문적으로 노력합니다. 그런 의미에서 저는 "학생"입니다. 나는 아주 기본적인 질문을합니다. 그것이 바로 그런 방식이기 때문입니다. 나는 내가하고있는 일을 왜하고 있는지 정확히 알고 싶습니다. 문제의 핵심. 그것을 얻지 못하면 마음에 들지 않고 질문을 시작합니다. 사용하려고한다면 이유를 알아야합니다. TDD는 무언가를 만들고 생각하는 데 필요한 것을 아는 것과 같은 방식으로 직관적으로 좋아 보이지만 구현을 이해하기 어려웠습니다. 나는 지금 더 잘 이해하고 있다고 생각합니다.
johnny


4
이것이 TDD의 규칙입니다. 원하는 코드를 자유롭게 작성할 수 있지만이 세 가지 규칙을 따르지 않으면 TDD를 수행하지 않는 것입니다.
Sean Burton

2
한 사람의 "규칙"? TDD는 종교가 아니라 코드 작성을 돕는 제안입니다. 너무 많은 사람들이 아이디어를 그렇게 간신히 고수하는 것은 슬픈 일입니다. TDD의 기원조차 논란의 여지가 있습니다.
user3791372

2
@ user3791372 TDD는 매우 엄격하고 명확하게 정의 된 프로세스입니다. 많은 사람들이 "프로그래밍 할 때 테스트를 수행하라"는 의미 만 있다고 생각하는 것은 아닙니다. 여기서 용어를 혼용하지 않도록합시다.이 질문은 일반적인 테스트가 아니라 프로세스 TDD에 관한 것입니다.
Alex
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.