TDD에서 프로덕션 코드를 수정하지 않고 통과 한 테스트 사례를 작성하면 무엇을 의미합니까? 더 이상 작성할

다음은 TDD에 대한 Robert C. Martin의 규칙입니다 .

  • 실패한 단위 테스트를 통과하지 않으면 프로덕션 코드를 작성할 수 없습니다.
  • 실패하기에 충분한 단위 테스트를 더 이상 작성할 수 없습니다. 컴파일 실패는 실패입니다.
  • 실패한 단위 테스트를 통과하기에 충분한 양보다 더 많은 생산 코드를 작성할 수 없습니다.

가치가 있지만 테스트 코드를 변경하지 않고 통과하는 테스트를 작성할 때 :

  1. 내가 잘못했음을 의미합니까?
  2. 도움이 될 수 있다면 앞으로 이러한 테스트를 작성하지 않아야합니까?
  3. 그 시험을 그 곳에 두거나 제거해야합니까?

참고 : 나는 이 질문을 여기 에서 시도 하고 있었다 : 통과하는 단위 테스트로 시작할 수 있습니까? 그러나 지금까지 질문을 충분히 설명 할 수 없었습니다.



답변

그것은 실패한 단위 테스트를 통과하지 않으면 프로덕션 코드를 작성할 수 없으며 시작부터 통과하는 테스트를 작성할 수는 없다고 말합니다. 규칙의 의도는 “제작 코드를 편집해야하는 경우 먼저 테스트를 작성하거나 테스트해야합니다.”라고 말합니다.

때때로 우리는 이론을 증명하기 위해 테스트를 작성합니다. 시험은 통과하고 우리의 이론을 반증합니다. 그런 다음 테스트를 제거하지 않습니다. 그러나 (소스 제어의 지원을 알고 있음) 프로덕션 코드가 중단되어 예상하지 못한 코드가 통과 한 이유를 이해할 수 있습니다.

테스트가 유효하고 올바른 것으로 판명되고 기존 테스트와 중복되지 않는 경우 그대로 두십시오.


답변

다음 중 하나를 의미합니다.

  1. 먼저 테스트를 작성하지 않고 원하는 기능을 수행하는 프로덕션 코드를 작성했거나 ( “종교적 TDD”위반) 또는
  2. 필요한 기능은 이미 프로덕션 코드로 이행되었으며 해당 기능을 다루기 위해 다른 단위 테스트를 작성하고 있습니다.

후자의 상황은 생각보다 일반적입니다. 완전히 불분명하고 사소한 (아직도 여전히 예시적인) 예로써, 다음과 같은 단위 테스트 (가짜이기 때문에 의사 코드)를 작성했다고 가정 해 봅시다.

public void TestAddMethod()
{
    Assert.IsTrue(Add(2,3) == 5);
}

실제로 필요한 것은 2와 3을 더한 결과입니다.

구현 방법은 다음과 같습니다.

public int add(int x, int y)
{
    return x + y;
}

그러나 이제 4와 6을 더해야한다고 가정 해 봅시다.

public void TestAddMethod2()
{
    Assert.IsTrue(Add(4,6) == 10);
}

나는 이미 두 번째 경우를 다루기 때문에 내 방법을 다시 작성할 필요가 없습니다.

이제 Add 함수가 실제로 한도를 가진 숫자를 반환해야한다는 것을 알았습니다 .100이라고 가정 해 보겠습니다.이를 테스트하는 새로운 메소드를 작성할 수 있습니다.

public void TestAddMethod3()
{
    Assert.IsTrue(Add(100,100) == 100);
}

그리고이 테스트는 이제 실패 할 것입니다. 이제 내 기능을 다시 작성해야합니다

public int add(int x, int y)
{
    var a = x + y;
    return a > 100 ? 100 : a;
}

통과시키기 위해.

상식에 따르면

public void TestAddMethod2()
{
    Assert.IsTrue(Add(4,6) == 10);
}

통과하면 테스트가 실패하도록 새 코드를 작성할 수 있도록 실패한 테스트를 가질 수 있도록 의도적으로 메소드를 실패 하게 하지 않습니다 .


답변

당신의 시험은 통과하지만 당신은 틀리지 않습니다. 프로덕션 코드가 처음부터 TDD가 아니기 때문에 발생했다고 생각합니다.

정식 (?) TDD를 가정 해 봅시다. 프로덕션 코드는 없지만 몇 가지 테스트 사례가 있습니다 (물론 항상 실패합니다). 전달할 프로덕션 코드를 추가합니다. 그런 다음 여기서 더 이상 실패한 테스트 사례를 추가하십시오. 다시 전달할 프로덕션 코드를 추가하십시오.

다시 말해, 테스트는 단순한 TDD 단위 테스트가 아닌 일종의 기능 테스트 일 수 있습니다. 이는 제품 품질에있어 항상 귀중한 자산입니다.

나는 개인적으로 전체주의적이고 비인간적 인 규칙을 좋아하지 않습니다.


답변

실제로 지난 밤 도조에서 같은 문제가 발생했습니다.

나는 그것에 대해 빠른 연구를했다. 이것이 내가 생각해 낸 것입니다.

기본적으로 TDD 규칙에 의해 명시 적으로 금지되지 않습니다. 함수가 일반화 된 입력에 대해 올바르게 작동 함을 증명하기 위해 추가 테스트가 필요할 수 있습니다. 이 경우 TDD 실습은 잠시 동안 그대로 유지됩니다. 그 사이에 생산 코드가 추가되지 않는 한 TDD 실습을 짧게 남겨 두는 것이 반드시 TDD 규칙을 어기는 것은 아닙니다.

중복되지 않는 한 추가 테스트를 작성할 수 있습니다. 동등한 클래스 분할 테스트를 수행하는 것이 좋습니다. 즉, 모든 동등성 등급에 대한 엣지 케이스와 하나 이상의 내부 케이스가 테스트됨을 의미합니다.

그러나이 방법으로 발생할 수있는 한 가지 문제는 테스트가 처음부터 통과되면 오 탐지가 없다는 것을 확신 할 수 없다는 것입니다. 테스트가 올바르게 구현되지 않고 프로덕션 코드가 올바르게 작동하지 않아 테스트가 통과 할 수 있음을 의미합니다. 이를 방지하려면 테스트를 중단하기 위해 생산 코드를 약간 변경해야합니다. 이로 인해 테스트가 실패하면 테스트가 올바르게 구현되고 프로덕션 코드를 다시 변경하여 테스트를 다시 통과시킬 수 있습니다.

엄격한 TDD를 연습하고 싶다면 처음부터 통과하는 추가 테스트를 작성하지 않을 수 있습니다. 반면에 엔터프라이즈 개발 환경에서는 추가 테스트가 유용 할 경우 실제로 TDD 실습을 떠나야합니다.


답변

프로덕션 코드를 수정하지 않고 통과하는 테스트는 본질적으로 나쁘지 않으며 추가 요구 사항이나 경계 사례를 설명하는 데 종종 필요합니다. 귀하의 시험이 “가치있는 것”으로 판단되는 한, 귀하의 시험은 유지하십시오.

문제가 발생하는 곳은 문제 영역을 실제로 이해하기위한 대안으로 이미 통과 한 테스트를 작성할 때입니다.

우리는 두 가지 극단적 인 상황을 상상할 수있다. 하나의 프로그래머가 “만약을 대비하여”많은 수의 테스트를 작성하면 하나의 버그를 발견 할 수있다. 최소한의 테스트를 작성하기 전에 문제 공간을 신중하게 분석하는 두 번째 프로그래머. 둘 다 절대 값 함수를 구현하려고한다고 가정 해 봅시다.

첫 번째 프로그래머는 다음과 같이 씁니다.

assert abs(-88888) == 88888
assert abs(-12345) == 12345
assert abs(-5000) == 5000
assert abs(-32) == 32
assert abs(46) == 46
assert abs(50) == 50
assert abs(5001) == 5001
assert abs(999999) == 999999
...

두 번째 프로그래머는 다음과 같이 씁니다.

assert abs(-1) == 1
assert abs(0) == 0
assert abs(1) == 1

첫 번째 프로그래머의 구현 결과는 다음과 같습니다.

def abs(n):
    if n < 0:
        return -n
    elif n > 0:
        return n

두 번째 프로그래머의 구현 결과는 다음과 같습니다.

def abs(n):
    if n < 0:
        return -n
    else:
        return n

모든 테스트는 통과했지만 첫 번째 프로그래머는 여러 중복 테스트를 작성했을뿐 아니라 (개발주기를 늦출 필요없이) 경계 사례를 테스트하지 못했습니다 ( abs(0)).

프로덕션 코드를 수정하지 않고 통과하는 테스트를 작성하는 경우 테스트가 실제로 가치를 추가하는지 또는 문제 공간을 이해하는 데 더 많은 시간을 소비해야하는지 스스로에게 문의하십시오.


답변