부정 행위없이 단위 테스트를 통과하기위한 최소 코드 작성!


36

TDD를 수행하고 단위 테스트를 작성할 때 테스트중인 "구현"코드의 첫 번째 반복을 작성할 때 "치트"하려는 충동에 어떻게 저항합니까?

예를 들어 :
숫자의 계승을 계산해야합니다. 다음과 같은 단위 테스트 (MSTest 사용)로 시작합니다.

[TestClass]
public class CalculateFactorialTests
{
    [TestMethod]
    public void CalculateFactorial_5_input_returns_120()
    {
        // Arrange
        var myMath = new MyMath();
        // Act
        long output = myMath.CalculateFactorial(5);
        // Assert
        Assert.AreEqual(120, output);
    }
}

이 코드를 실행하면 CalculateFactorial메서드가 존재하지 않기 때문에 실패 합니다. 이제 테스트중인 메소드를 구현하기 위해 코드의 첫 번째 반복을 작성 하여 테스트를 통과하는 데 필요한 최소 코드를 작성합니다 .

문제는 계속해서 다음과 같이 작성하고 싶은 유혹입니다.

public class MyMath
{
    public long CalculateFactorial(long input)
    {
        return 120;
    }
}

이것은 점에서 정확한 기술적 인 정말 하는 데 필요한 최소 코드 특정 테스트 통과를 만들기 는 정말도하지 않기 때문에 A는 "속임수"분명히 비록, (친환경) 을 시도 계승을 계산하는 기능을 수행 할 수 있습니다. 물론, 이제 리팩토링 부분은 실제 구현의 리팩토링이 아닌 "올바른 기능을 작성"하는 연습이되었습니다. 분명히 다른 매개 변수로 테스트를 추가하면 리팩토링이 실패하지만 해당 테스트로 시작해야합니다.

그래서 제 질문은 "테스트를 통과하기 위해 최소 코드를 작성하는 것"과 기능을 유지하면서 실제로 달성하려는 정신에 대한 균형을 어떻게 얻습니까?


4
그것은 인간의 것입니다 : 부정 행위에 대한 충동에 저항해야합니다. 더 이상 아무것도 없습니다. 테스트 할 코드보다 더 많은 테스트를 추가하고 더 많은 테스트 코드를 작성할 수 있지만 그러한 사치가 없다면 저항해야합니다. 오늘날에도 작동하지만 나중에는 작동하지 않는다는 것을 알고 있기 때문에 우리는 코딩이나 해킹이나 치트에 대한 충동에 저항해야하는 많은 장소가 있습니다.
Dan Rosenstark

7
확실히, TDD에서, 다른 방법으로 부정 행위를하는 것은 속임수입니다. 즉, 리턴 120이 올바른 방법입니다. 나는 그렇게하기가 매우 어려우며 앞서 나가지 않고 계승 계산을 작성하기 시작합니다.
Paul Butcher

2
테스트를 통과 할 수는 있지만 진정한 기능을 추가하거나 현재 문제에 대한 최종 솔루션에 더 가까이 가지 않기 때문에 이것이 사기라고 생각합니다.
GrumpyMonkey 19시 06 분

3
클라이언트 코드 코드가 5로만 통과한다는 것이 밝혀지면 120을 반환하는 것은 사기가 아니라 실제로 합법적 인 솔루션입니다.
Kramii Reinstate Monica

@PaulButcher에 동의합니다. 실제로 텍스트와 기사의 많은 단위 테스트 예제 가이 접근법을 취합니다.
HorusKol

답변:


45

완벽하게 합법적입니다. 빨강, 녹색, 리 팩터.

첫 번째 시험에 합격합니다.

새로운 입력으로 두 번째 테스트를 추가하십시오.

이제 녹색으로 빠르게 전환하면 if-else를 추가 할 수 있습니다. 통과하지만 아직 완료되지 않았습니다.

빨강, 초록, 리 팩터의 세 번째 부분이 가장 중요합니다. 중복 제거 리팩터링 . 이제 코드에 중복이 생길 것입니다. 정수를 리턴하는 두 개의 명령문. 그리고 그 중복을 제거하는 유일한 방법은 함수를 올바르게 코딩하는 것입니다.

처음에는 올바르게 쓰지 않는다고 말하는 것이 아닙니다. 당신이하지 않으면 부정 행위가 아니라고 말하는 것입니다.


12
이것은 단지 질문을 제기합니다. 왜 처음에 함수를 올바르게 작성하지 않습니까?
Robert Harvey

8
@Robert, 계승 수는 아주 간단합니다. TDD의 실제 장점은 사소하지 않은 라이브러리를 작성하고 테스트를 먼저 작성하면 구현 전에 API를 설계해야한다는 것입니다.

1
@Robert, 당신은 테스트를 통과하는 대신 문제 해결을 걱정하고 있습니다. 사소한 문제가 아닌 경우 테스트를 실시 할 때까지 하드 디자인을 연기하는 것이 더 효과적이라고 말하고 있습니다.

1
@ Thorbjørn Ravn Andersen, 아니요, 한 번만 돌아올 수는 없습니다. 여러 가지 유효한 이유가 있습니다 (예 : 보호문). 문제는 두 반환 문이 "동일"하다는 것입니다. 그들은 같은 '일'을했다. 그들은 방금 다른 가치를 가졌습니다. TDD는 강성이 아니며 특정 크기의 테스트 / 코드 비율을 준수합니다. 코드 기반 내에서 편안한 수준을 만드는 것입니다. 당신이 실패한 테스트를 작성할 수 있다면, 그 함수의 미래 테스트를 위해 작동하는 함수는 훌륭합니다. 그런 다음 기능이 여전히 작동하는지 확인하는 엣지 케이스 테스트를 작성하십시오.
CaffGeek

3
한 번에 전체 (간단하지만) 구현을 작성하지 않는 점은 테스트조차도 실패 할 것이라는 보장이 전혀 없다는 것입니다. 테스트를 통과하기 전에 테스트가 실패하는 것은 코드 변경이 사용자가 작성한 어설 션을 만족시키는 것이라는 실제 증거가 있다는 것입니다. 이것이 TDD가 회귀 테스트 스위트를 구축하는 데 큰 이유이며 그 의미에서 "테스트 후"접근 방식으로 바닥을 완전히 닦는 유일한 이유입니다.
sara mar

25

궁극적 인 목표에 대한 이해와 그 목표를 충족하는 알고리즘의 달성이 필요합니다.

TDD는 디자인의 마법의 총알이 아닙니다. 여전히 코드를 사용하여 문제를 해결하는 방법을 알아야하며, 테스트 통과를 위해 몇 줄의 코드보다 높은 수준에서이를 수행하는 방법을 알아야합니다.

나는 좋은 디자인을 장려하기 때문에 TDD의 아이디어를 좋아한다. 테스트 할 수 있도록 코드를 작성하는 방법을 생각하게하며 일반적으로 철학은 코드를 전체적으로 더 나은 디자인으로 이끌 것입니다. 그러나 여전히 솔루션을 설계하는 방법을 알아야합니다.

테스트를 통과하기 위해 가장 적은 양의 코드를 작성하여 응용 프로그램을 개발할 수 있다고 주장하는 축소주의 TDD 철학을 선호하지 않습니다. 건축에 대해 생각하지 않으면 이것은 작동하지 않으며 귀하의 예는 그것을 증명합니다.

밥 마틴 삼촌 은 이렇게 말합니다.

테스트 주도 개발을 수행하지 않으면 전문가라고 부르기가 매우 어렵습니다. 짐 코 플린 (Jim Coplin)이 카펫에 나를 불렀습니다. 그는 내가 그 말을 좋아하지 않았다. 실제로, 그의 직책은 사람들이 다른 종류의 생각을 포기하기 위해 테스트를 작성하고 미친 듯이 급히 시험을 통과하기 위해 아키텍처를 찢어서 흥미로운 포인트를 얻었 기 때문에 테스트 주도 개발은 아키텍처를 파괴하는 것입니다. 그것은 의식을 남용하고 징계 뒤에 의도를 잃는 흥미로운 방법입니다.

건축을 생각하지 않는다면 건축을 무시하고 테스트를 함께 던지고 통과시키는 것이 건물에 집중하기 때문에 건물을 유지할 수있는 것을 파괴하는 것입니다. 시스템의 구조와 시스템의 구조적 무결성을 유지하는 데 도움이되는 견고한 설계 결정.

단순히 수많은 테스트를 함께 던져 10 년 후 10 년 동안 통과시켜 시스템이 생존 할 것이라고 가정 할 수는 없습니다. 우리는 스스로를 지옥으로 진화시키고 싶지 않습니다. 따라서 좋은 테스트 주도 개발자는 항상 아키텍처 결정을 내릴 때 항상 큰 그림을 생각합니다.


실제로 질문에 대한 대답은 아니지만 1+
아무도

2
@rmx : 음, 문제는 : "테스트를 통과하기위한 최소 코드 작성"과 기능을 유지하면서 실제로 달성하려는 목표의 정신 사이에서 어떻게 균형을습니까? 우리는 같은 질문을 읽고 있습니까?
Robert Harvey

이상적인 솔루션은 알고리즘이며 아키텍처와 관련이 없습니다. TDD를 수행한다고해서 알고리즘이 발명되지는 않습니다. 어떤 시점에서 알고리즘 / 솔루션 측면에서 단계를 수행해야합니다.
Joppe

@rmx에 동의합니다. 이것은 실제로 내 특정 질문에 대한 답은 아니지만 TDD가 전반적인 소프트웨어 개발 프로세스의 큰 그림에 어떻게 적용되는지에 대한 생각을 불러 일으 킵니다. 따라서 +1입니다.
CraigTP

"아키텍처"대신 "알고리즘"과 다른 용어를 대신 할 수 있다고 생각합니다. 나무의 나무를 볼 수 없다는 것입니다. 모든 단일 정수 입력에 대해 별도의 테스트를 작성하지 않는 한, TDD는 적절한 계승 구현과 테스트 된 모든 경우에 작동하는 다른 하드 코딩을 구별 할 수 없습니다. TDD의 문제점은 "모든 테스트를 통과"하고 "코드가 양호하다"는 것이 용이하다는 것입니다. 어떤 시점에서 상식에 대한 막대한 측정이 적용되어야합니다.
Julia Hayward

16

아주 좋은 질문입니다 ... 그리고 @Robert를 제외한 거의 모든 사람들과 동의하지 않아야합니다.

쓰기

return 120;

한 번의 테스트 통과를위한 계승 함수 는 시간 낭비입니다 . 그것은 "속임수"가 아니며 문자 그대로 적 녹색 리 팩터를 따르지 않습니다. 그것은이다 잘못된 .

이유는 다음과 같습니다.

  • 계승 계산 은 "상수 반환"이 아닌 피처입니다. "return 120"은 계산 이 아닙니다 .
  • '리 팩터'논증은 잘못 인도되었다; 5와 6에 대한 두 가지 테스트 사례가있는 경우 계승 을 전혀 계산하지 않기 때문에이 코드는 여전히 잘못 되었습니다 .

    if (input == 5) { return 120; } //input=5 case
    else { return 720; }   //input=6 case
    
  • 문자 그대로 'refactor'인수를 따르는 경우 5 개의 테스트 사례가있을 때 YAGNI를 호출하고 찾아보기 테이블을 사용하여 함수를 구현합니다.

    if (factorialDictionary.Contains(input)) {
        return factorialDictionary[input]; 
    }
    throw new Exception("Input failure");
    

이 중 어느 것도 실제로 아무것도 계산 하지 않습니다 . 그리고 그것은 임무가 아닙니다!


1
@rmx : 아뇨, 놓치지 않았습니다. 찾아보기 테이블을 사용하여 "중복 제거 리 팩터"를 만족시킬 수 있습니다. BTW 단위 테스트 인코딩 요구 사항은 BDD에만 국한된 것이 아니라 Agile / XP의 일반적인 원칙입니다. 요구 사항이 " '5의 계승이 무엇입니까?"라는 질문에 대답하면'120을 리턴하십시오. ' 합법적 일 것이다 ;-)
Steven A. Lowe

2
@Chad는 모두 불필요한 작업입니다-처음으로 함수를 작성하십시오. ;-)
Steven A. Lowe

2
@Steven A.Lowe, 그 논리에 의해 왜 테스트를 작성해야합니까?! "처음으로 응용 프로그램을 작성하십시오!" TDD의 요점은 작고 안전하며 점진적인 변경입니다.
CaffGeek

1
@ 차드 : strawman.
Steven A. Lowe

2
한 번에 전체 (간단하지만) 구현을 작성하지 않는 점은 테스트조차도 실패 할 것이라는 보장이 전혀 없다는 것입니다. 테스트를 통과하기 전에 테스트가 실패하는 것은 코드 변경이 사용자가 작성한 어설 션을 만족시키는 것이라는 실제 증거가 있다는 것입니다. 이것이 TDD가 회귀 테스트 스위트를 구축하는 데 큰 이유이며 그 의미에서 "테스트 후"접근 방식으로 바닥을 완전히 닦는 유일한 이유입니다. 실수로 실패 할 수없는 테스트를 작성하지 마십시오. 또한 멍청이 밥 주요 요인 카타를 살펴보십시오.
sara mar

10

단 하나의 단위 테스트 만 작성한 경우 한 줄 구현 ( return 120;)이 합법적입니다. 120의 값을 계산하는 루프를 작성하면 부정 행위가됩니다!

이러한 간단한 초기 테스트는 에지 사례를 포착하고 일회성 오류를 방지하는 좋은 방법입니다. 실제로 5는 내가 시작할 입력 값이 아닙니다.

여기서 유용 할 수있는 경험 법칙은 0, 1, 많은, 많은 것 입니다. 계승의 중요한 가장자리 사례는 0과 1입니다. 그들은 하나의 라이너로 구현할 수 있습니다. "다수"테스트 사례 (예 : 5!)는 루프를 작성하도록 강제합니다. "lots"(1000 !?) 테스트 사례를 사용하면 매우 많은 수를 처리하는 대체 알고리즘을 구현할 수 있습니다.


2
"-1"사례는 흥미로울 것입니다. 잘 정의되어 있지 않기 때문에 테스트를 작성하는 사람과 코드를 작성하는 사람 모두 먼저 발생 해야하는 일 에 동의 해야합니다 .
gnasher729

2
실제로 지적하기에 +1 factorial(5)은 나쁜 첫 번째 테스트입니다. 우리는 가능한 가장 간단한 경우에서 시작하여 각 반복에서 테스트를 좀 더 구체적으로 만들고 코드를 좀 더 일반적인 것으로 만듭니다. 이것은 밥 아저씨가 변환 우선 순위 전제라고 부릅니다 ( blog.8thlight.com/uncle-bob/2013/05/27/… )
sara

5

테스트가 하나 뿐인 경우 테스트를 통과하는 데 필요한 최소 코드는 실제로 return 120;이므로 더 이상 테스트하지 않는 한 쉽게 유지할 수 있습니다.

이를 통해 실제로이 메소드의 OTHER 리턴 값을 실행하는 테스트를 작성할 때까지 추가 설계를 연기 할 수 있습니다.

테스트는 사양의 실행 가능한 버전이며, 해당 사양 이 모두 f (6) = 120 인 경우 청구서에 완벽하게 맞는다는 것을 기억하십시오.


진심이야? 이 논리에 따라 누군가 새로운 입력을 할 때마다 코드를 다시 작성해야합니다.
Robert Harvey

6
@Robert, 어떤 경우에는 새로운 사례를 추가해도 더 이상 가장 간단한 코드 가 생성되지 않으며 ,이 시점에서 새로운 구현을 작성합니다. 테스트가 이미 준비되어 있으므로 새 구현이 이전 구현과 동일한시기를 정확하게 알고 있습니다.

1
Red-Green-Refactor의 가장 중요한 부분 인 @ Thorbjørn Ravn Andersen은 리팩토링입니다.
CaffGeek

+1 : 이것은 내 지식의 일반적인 아이디어이지만 암시 적 계약 이행 (즉, 메소드 이름 factorial )에 대해 언급해야합니다 . f (6) = 120 만 지정하면 (예 : 테스트) '120을 반환'하면됩니다. f (x) == x * x-1 ... * xx-1 : upperBound> = x> = 0임을 확인하기 위해 테스트를 추가하기 시작하면 계승 방정식을 만족하는 함수에 도달합니다.
Steven Evers

1
@SnOrfus, "암시 적 계약"의 장소는 테스트 사례입니다. 계승에 대한 계약 인 경우 알려진 계승이 있고 알려진 비 계승이 아닌 경우 테스트 합니다. 그들 중 다수. 열 번째 계승의 목록을 열 번째 계승까지 모든 수의 루프 테스트로 변환하는 데 오래 걸리지 않습니다.

4

그러한 방법으로 "속임수"를 할 수 있다면 단위 테스트에 결함이있는 것입니다.

단일 값으로 계승 법을 테스트하는 대신 값의 범위인지 테스트하십시오. 여기에서 데이터 중심 테스트가 도움이 될 수 있습니다.

단위 테스트를 요구 사항의 표현으로 봅니다. 테스트하는 방법의 동작을 집합 적으로 정의해야합니다. (이것은 행동 주도 개발 로 알려져 있습니다 -미래 ;-))

누군가에게 구현을 잘못된 것으로 변경하려는 경우 테스트가 여전히 통과하거나 "일시 중단"이라고 말합니까?

그것을 염두에두고, 유일한 테스트가 귀하의 질문에 대한 테스트라면 기술적으로 해당 구현이 정확합니다. 그런 다음 문제는 잘 정의되지 않은 요구 사항으로 간주됩니다.


nanda가 지적했듯이 항상 무한한 일련의 case명령문을에 추가 switch할 수 있으며 OP의 예제에 대해 가능한 모든 입력 및 출력에 대한 테스트를 작성할 수 없습니다.
Robert Harvey

당신은 기술적으로의 값을 테스트 할 수 있습니다 Int64.MinValueInt64.MaxValue. 실행하는 데 시간이 오래 걸리지 만 오류의 여지없이 요구 사항을 명시 적으로 정의합니다. 현재의 기술로는 이것이 실현 불가능합니다 (향후 더 흔해질 것이라고 생각합니다). 당신은 속일 수는 있지만 OPs 질문은 실용적인 것이 아니라고 생각합니다 (아무도 실제로 그러한 방식으로 속이지는 않을 것입니다) 실제로)하지만 이론적 인 것입니다.
아무도

@rmx : 그렇게하면 테스트가 알고리즘이 되고 더 이상 알고리즘을 작성할 필요가 없습니다.
Robert Harvey

사실입니다. 내 대학 논문은 실제로 TDD를 지원하기 위해 유전자 알고리즘을 이용한 가이드로 단위 테스트를 사용하여 구현의 자동 생성을 포함하며 이는 견고한 테스트에서만 가능합니다. 차이점은 일반적으로 단위 테스트를 구현하는 단일 방법보다 요구 사항을 코드에 바인딩하는 것이 읽기 쉽고 파악하기가 훨씬 어렵다는 것입니다. 그렇다면 구현이 단위 테스트의 표현이고 단위 테스트가 요구 사항을 나타내는 경우 테스트를 건너 뛰지 않는 이유는 무엇입니까? 나는 대답이 없다.
아무도

또한, 우리는 구현 코드에서와 같이 단위 테스트에서 실수를 저지르는 것처럼 인간이 아닌가? 그렇다면 왜 단위 테스트가 필요합니까?
아무도

3

더 많은 테스트를 작성하십시오. 결국, 것입니다 짧은 쓰기

public long CalculateFactorial(long input)
{
    return input <= 1 ? 1 : CalculateFactorial(input-1)*input;
}

...보다

public long CalculateFactorial(long input)
{
    switch (input) {
       case 0: return 1;
       case 1: return 1;
       case 2: return 2;
       case 3: return 6;
       case 4: return 24;
       case 5: return 120;
    }
}

:-)


3
처음에는 알고리즘을 올바르게 작성하지 않습니까?
Robert Harvey

3
@Robert, 그것은 0에서 5까지의 숫자의 계승을 계산 하는 올바른 알고리즘입니다. 게다가, "정확하게"는 무엇을 의미합니까? 이것은 매우 간단한 예이지만 더 복잡해지면 "올바른"의 의미에 대한 많은 그라데이션이 생깁니다. 루트 액세스가 필요한 프로그램이 "정확한"것입니까? CSV를 사용하는 대신 XML을 "올바르게"사용하고 있습니까? 당신은 이것에 대답 할 수 없습니다. TDD에서 테스트로 공식화되는 일부 비즈니스 요구 사항을 충족하는 한 모든 알고리즘이 정확합니다.
P Shved

3
출력 유형이 길기 때문에 함수가 올바르게 처리 할 수있는 입력 값 (20 정도)이 적기 때문에 큰 스위치 명령문이 반드시 최악의 구현은 아닙니다-속도가 더 높을 경우 코드 크기보다 중요한 경우, switch 문은 우선 순위에 따라 갈 수 있습니다.
user281377

3

"치트"테스트 작성은 "OK"의 값이 충분히 작 으면 괜찮습니다. 그러나 리콜 장치 테스트는 모든 테스트가 통과 되고 실패 할 새 테스트를 작성할 수없는 경우에만 완료됩니다 . 많은 if 문 (또는 더 나은 큰 switch / case 문 :-) 을 포함하는 CalculateFactorial 메서드를 실제로 원한다면 그렇게 할 수 있으며 고정 소수점 숫자를 처리하기 때문에 필요한 코드 이것을 구현하는 것은 유한합니다 (아마도 크거나 추하고, 아마도 프로 시저 코드의 최대 크기에 대한 컴파일러 또는 시스템 제한에 의해 제한 될 수 있습니다). 이 시점에서 당신이 정말로모든 개발을 단위 테스트로 추진해야한다고 주장하면 if 문의 모든 분기를 따라 수행 할 수있는 것보다 짧은 시간 내에 결과를 계산하는 코드를 요구하는 테스트를 작성할 수 있습니다 .

기본적으로 TDD를 사용하면 요구 사항을 올바르게 구현하는 코드 작성할 수 있지만 좋은 코드 를 작성하도록 강요 할 수는 없습니다 . 그것은 당신에게 달려 있습니다.

공유하고 즐기십시오.


"단위 테스트는 모든 테스트를 통과하고 실패 할 새로운 테스트를 작성할 수 없을 때에 만 완료됩니다"+1 많은 사람들이 합법적으로 상수를 반환한다고 말하지만 "단기"또는 "단기"를 따르지 않습니다. 전체 요구 사항에 특정 사례 만 필요한 경우 "
Thymine

1

나는 Robert Harveys의 제안에 100 % 동의합니다. 테스트를 통과하는 것이 아니라 전반적인 목표를 염두에 두어야합니다.

"지정된 입력 세트로만 작동하는 것으로 확인되었습니다"라는 문제에 대한 해결책으로 xunit 이론과 같은 데이터 기반 테스트를 사용하는 것이 좋습니다. 이 개념의 힘은 출력에 대한 입력 사양을 쉽게 만들 수 있다는 것입니다.

팩토리얼의 경우 테스트는 다음과 같습니다.

    [Theory]
    [InlineData(0, 1)]
    [InlineData( 1, 1 )]
    [InlineData( 2, 2 )]
    [InlineData( 3, 6 )]
    [InlineData( 4, 24 )]
    public void Test_Factorial(int input, int expected)
    {
        int result = Factorial( input );
        Assert.Equal( result, expected);
    }

테스트 데이터 제공 (을 반환 IEnumerable<Tuple<xxx>>)을 구현하고 수학 불변량을 인코딩 할 수 있습니다 ( 예 : n을 반복해서 나누면 n-1이 생성됨).

이 tp는 매우 강력한 테스트 방법입니다.


1

여전히 속임수를 쓰면 테스트가 충분하지 않습니다. 더 많은 테스트를 작성하십시오! 예를 들어, 입력 1, -1, -1000, 0, 10, 200으로 테스트를 추가하려고합니다.

그럼에도 불구하고, 당신이 정말로 부정 행위를한다면, 끝없는 if-then을 쓸 수 있습니다. 이 경우 코드 검토 외에는 도움이되지 않습니다. 합격 시험에 곧 붙잡 힐 것입니다 ( 다른 사람이 작성했습니다! )

단위 테스트의 문제점은 때때로 프로그래머가이를 불필요한 작업으로 간주한다는 것입니다. 그것들을 보는 올바른 방법은 작업 결과를 올바르게 만드는 도구입니다. 따라서 if-then을 작성하면, 고려해야 할 다른 경우가 있다는 것을 무의식적으로 알고 있습니다. 이것은 다른 테스트를 작성해야 함을 의미합니다. 그리고 부정 행위가 작동하지 않는다는 것을 깨달을 때까지 계속해서 올바른 방식으로 코딩하는 것이 좋습니다. 여전히 완료되지 않았다고 생각되면 완료되지 않은 것입니다.


1
따라서 테스트를 통과하기에 충분한 코드를 작성하는 것만으로는 충분하지 않습니다 (TDD가 주장하는 것처럼) . 또한 건전한 소프트웨어 디자인 원칙을 염두에 두어야합니다. BTW에 동의합니다.
Robert Harvey

0

나는 당신이 선택한 시험이 최선의 시험이 아니라고 제안합니다.

나는 시작합니다 :

첫 번째 검정 인 factorial (1)

두 번째로 계승 (0)

세번째 계승 (-ve)

그리고 사소한 경우로 계속 진행하십시오.

오버플로 사례로 마무리하십시오.


무엇입니까 -ve??
Robert Harvey

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