결과를 예측하기 어려운 코드에 대한 단위 테스트를 어떻게 작성합니까? 시간은 역 일 perDay에 의해 조정됩니다. 누산기를

나는 함수의 정확한 결과를 미리 예측하기 어려운 수치 적 / 수학적 프로그램을 자주 사용합니다.

이런 종류의 코드로 TDD를 적용하려고 할 때 종종 테스트중인 코드를 작성하는 것이 코드에 대한 단위 테스트를 작성하는 것보다 훨씬 쉽다는 것을 알았습니다. 예상 결과를 찾는 유일한 방법은 알고리즘 자체를 적용하는 것입니다. 머리, 종이 또는 컴퓨터). 나는 다른 방법 대신에 테스트중인 코드를 효과적으로 사용하여 단위 테스트를 확인하고 있기 때문에 잘못된 느낌입니다.

테스트중인 코드의 결과를 예측하기 어려운 경우 단위 테스트를 작성하고 TDD를 적용하는 알려진 기술이 있습니까?

결과를 예측하기 어려운 코드의 실제 예 :

함수 weightedTasksOnTime하루에 할 일의 양을 주어진 workPerDay범위 (0, 24], 현재 시간 initialTime> 0, 및 작업의 목록을 taskArray각 시간과 재산 완료 time> 0, 마감일 due및 중요성 값을 importance, 반환 에서 시작 due하는 순서대로 각 작업을 완료 한 경우 날짜 이전에 완료 할 수있는 작업의 중요도를 나타내는 [0, 1] 범위의 정규화 된 값 .taskArrayinitialTime

이 기능을 구현하는 알고리즘은 비교적 간단합니다 taskArray.의 작업을 반복합니다 . 각 작업의 경우, 추가 timeinitialTime. 새로운 시간 < due이면 importance누산기에 추가하십시오 . 시간은 역 일 perDay에 의해 조정됩니다. 누산기를 반환하기 전에 작업 중요도를 합하여 정규화하십시오.

function weightedTasksOnTime(workPerDay, initialTime, taskArray) {
    let simulatedTime = initialTime
    let accumulator = 0;
    for (task in taskArray) {
        simulatedTime += task.time * (24 / workPerDay)
        if (simulatedTime < task.due) {
            accumulator += task.importance
        }
    }
    return accumulator / totalImportance(taskArray)
}

위의 문제는 단순화 workPerDay하고 정규화 요구 사항 을 제거하여 핵심을 유지하면서 다음과 같이 할 수 있다고 생각합니다 .

function weightedTasksOnTime(initialTime, taskArray) {
    let simulatedTime = initialTime
    let accumulator = 0;
    for (task in taskArray) {
        simulatedTime += task.time
        if (simulatedTime < task.due) {
            accumulator += task.importance
        }
    }
    return accumulator
}

이 질문은 테스트중인 코드가 기존 알고리즘을 다시 구현하지 않는 상황을 해결합니다. 코드가 재 구현 된 경우 알고리즘의 기존 신뢰할 수있는 구현이 자연스러운 테스트 오라클 역할을하기 때문에 본질적으로 결과를 쉽게 예측할 수 있습니다.



답변

테스트하기 어려운 코드에서 테스트 할 수있는 두 가지가 있습니다. 첫째, 퇴화 사례입니다. 작업 배열에 요소가 없거나 하나 또는 두 개만 있고 하나만 기한이 지났을 경우 어떻게됩니까? 실제 문제보다 단순하지만 여전히 수동으로 계산하기에 합리적인 모든 것.

두 번째는 위생 검사입니다. 이러한 답변이 경우 당신이 모르는 곳에 당신이 검사입니다 하지만 있다면 당신은 확실히 알 것입니다 잘못된 . 시간은 앞으로 나아가 야하며, 값은 합리적인 범위에 있어야하며, 백분율은 최대 100이어야합니다.

예, 이것은 전체 테스트만큼 좋지는 않지만 완전성 검사를 엉망으로 만드는 경우가 얼마나 자주 놀라게되는지 알 수 있습니다. 이는 전체 알고리즘에 문제가 있음을 나타냅니다.


답변

나는 예측하기 어려운 출력으로 과학 소프트웨어에 대한 테스트를 작성했습니다. 우리는 변성 관계를 많이 사용했습니다. 기본적으로 정확한 수치 출력을 모르더라도 소프트웨어의 작동 방식에 대해 알고있는 것이 있습니다.

귀하의 경우에 가능한 예 : 매일 할 수있는 일의 양을 줄이면 할 수있는 총 일의 양은 동일하게 유지되지만 줄어들 가능성이 있습니다. 따라서 여러 값에 대해 함수를 실행하고 workPerDay관계가 유지되는지 확인하십시오.


답변

다른 답변에는 엣지 또는 오류 사례에 대한 테스트를 개발하기위한 좋은 아이디어가 있습니다. 다른 사람들에게는 알고리즘 자체를 사용하는 것이 이상적이지는 않지만 여전히 유용합니다.

알고리즘 (또는 의존하는 데이터)이 변경되었는지 감지합니다.

변경이 사고 인 경우 커밋을 롤백 할 수 있습니다. 변경이 의도적 인 경우 단위 테스트를 다시 방문해야합니다.


답변

다른 종류의 코드에 대해 단위 테스트를 작성하는 것과 같은 방법 :

  1. 대표적인 테스트 사례를 찾아 테스트하십시오.
  2. 최첨단 사례를 찾아 테스트합니다.
  3. 오류 조건을 찾아서 테스트하십시오.

코드에 임의의 요소가 포함되거나 결정적이지 않은 경우 (예 : 동일한 입력에서 동일한 출력을 생성하지 않음) 단위 테스트가 가능합니다.

부작용이나 외부 힘의 영향을받는 기능을 피하십시오. 순수한 기능은 테스트하기가 더 쉽습니다.


답변

의견이 게시되어 업데이트

간결하게하기 위해 원래 답변이 제거되었습니다. 편집 기록에서 찾을 수 있습니다.

PaintingInAir 상황 : 기업가이자 학문적으로 내가 디자인 한 대부분의 알고리즘은 본인 이외의 다른 사람이 요청하지 않습니다. 이 질문에 제시된 예는 작업 순서의 품질을 최대화하기위한 미분없는 옵티마이 저의 일부입니다. 내부적으로 예제 기능의 필요성을 어떻게 설명했는지에 대해서는 “제 시간에 완료되는 작업의 중요성을 극대화하기 위해 객관적인 기능이 필요합니다.” 그러나이 요청과 단위 테스트 구현 사이에는 여전히 큰 차이가있는 것으로 보입니다.

먼저 TL; DR 은 다른 긴 답변을 피합니다.

그것을 이런 식으로 생각 :
고객이 맥도날드를 입력하고 토핑과 같은 양상추, 토마토와 손을 비누와 햄버거를 요청합니다. 이 명령은 요리사가 요청한대로 버거를 만드는 요리사에게 제공됩니다. 고객은이 버거를 받아서 먹은 다음 맛있는 버거가 아니라고 요리사에게 불평합니다!

이것은 요리사의 잘못이 아닙니다. 고객이 명시 적으로 요청한 것만 수행합니다. 요청한 주문이 실제로 맛있는 지 확인하는 것은 요리사의 일이 아닙니다 . 요리사는 단순히 고객이 주문한 것을 만듭니다. 맛있는 것을 주문하는 것은 고객의 책임입니다 .

마찬가지로 알고리즘의 정확성에 의문을 제기하는 것은 개발자의 일이 아닙니다. 그들의 유일한 임무는 요청에 따라 알고리즘을 구현하는 것입니다.
단위 테스트는 개발자 도구입니다. 햄버거가 주문과 일치 함을 확인합니다 (부엌을 떠나기 전에). 그것은 주문 버거가 실제로 맛있다는 것을 확인하려고하지 않습니다.

해도 당신이 고객과 요리사 모두 의미있는 차이 사이는 여전히 존재한다 :

  • 나는이 식사를 제대로 준비하지 않았으며 맛이 좋지 않았습니다 (= 요리 오류). 구운 스테이크는 스테이크를 좋아하더라도 결코 맛이 좋을 것입니다.
  • 식사를 제대로 준비했지만 마음에 들지 않습니다 (= 고객 오류). 스테이크가 마음에 들지 않으면 스테이크를 완벽하게 요리하더라도 스테이크를 좋아하지 않습니다.

여기서 중요한 문제는 고객과 개발자 (및 분석가를 구분하지 않음)이지만 개발자가 해당 역할을 나타낼 수 있다는 것입니다.

코드 테스트와 비즈니스 요구 사항 테스트를 구별해야합니다.

예를 들어 고객은 [this] 와 같이 작동하기를 원합니다 . 그러나 개발자는 오해를하며 [that]하는 코드를 작성합니다 .

현상 따라서 만약 테스트 유닛 테스트 물품 것 [즉] 예상대로 작동한다. 그가 응용 프로그램을 올바르게 개발했다면 , 고객이 기대했던 응용 프로그램이 [this] 수행하지 않아도 단위 테스트는 통과 할 것 입니다.

고객의 기대 (비즈니스 요구 사항)를 테스트하려면 별도의 단계를 거쳐야합니다.

이러한 테스트를 언제 실행해야하는지 보여주는 간단한 개발 워크 플로 :

  • 고객이 해결하려는 문제를 설명합니다.
  • 분석가 (또는 개발자)는이를 분석에 기록합니다.
  • 개발자는 분석 내용을 설명하는 코드를 작성합니다.
  • 개발자 는 자신의 코드 (단위 테스트)를 테스트하여 분석을 올바르게 수행했는지 확인합니다.
  • 단위 테스트가 실패하면 개발자는 다시 개발로 돌아갑니다. 장치가 모든 테스트를 통과 할 때까지 무한정 반복됩니다.
  • 이제 테스트 (확인 및 통과) 된 코드 기반을 가지고있는 개발자는 응용 프로그램을 빌드합니다.
  • 응용 프로그램은 고객에게 제공됩니다.
  • 고객은 이제 자신이 제공 한 애플리케이션이 실제로 해결하려는 문제를 해결하는지 테스트합니다 (QA 테스트) .

고객과 개발자가 하나이고 동일한 경우 두 가지 개별 테스트를 수행하는 것이 무엇인지 궁금 할 것입니다. 개발자에서 고객으로의 “핸드 오프”가 없기 때문에 테스트는 차례로 실행되지만 여전히 별도의 단계입니다.

  • 단위 테스트는 개발 단계가 완료되었는지 확인하는 데 유용한 특수 도구입니다.
  • QA 테스트는 응용 프로그램사용하여 수행됩니다 .

알고리즘 자체가 올바른지 테스트 하려면 개발자의 작업이 아닙니다 . 이것이 고객의 관심사이며 고객은 애플리케이션 을 사용하여 이를 테스트 합니다.

기업가이자 학문적으로 중요한 책임을 잃어 버렸을 수 있습니다.

  • 애플리케이션이 고객이 처음 요청한 내용을 준수하지 않는 경우 코드의 후속 변경은 대개 무료로 수행 됩니다 . 개발자 오류이기 때문에. 개발자가 실수를했고 수정 비용을 지불해야합니다.
  • 애플리케이션이 고객이 처음 요청한 것을 수행하지만 이제 고객이 마음을 바꾼 경우 (예 : 더 우수하고 다른 알고리즘을 사용하기로 결정한 경우) 코드 기반 변경 사항 은 고객에게 청구 되지 않습니다. 고객이 현재 원하는 것과 다른 것을 요청했다는 개발자의 잘못. 마음을 바꾸는 것은 고객의 책임 (비용)이므로 개발자가 이전에 동의하지 않은 것을 개발하기 위해 더 많은 노력을 기울여야합니다.

답변

속성 테스트

때로는 수학적 기능이 전통적인 예제 기반 단위 테스트보다 “속성 테스트”에 의해 더 잘 제공됩니다. 예를 들어 정수 “곱하기”함수와 같은 단위 테스트를 작성한다고 가정하십시오. 함수 자체가 매우 단순 해 보일 수 있지만 그것이 곱하는 유일한 방법이라면 함수 자체의 논리없이 어떻게 철저하게 테스트합니까? 예상되는 입 / 출력으로 거대한 테이블을 사용할 수 있지만 이는 제한적이고 오류가 발생하기 쉽습니다.

이 경우 특정 예상 결과를 찾는 대신 함수의 알려진 속성을 테스트 할 수 있습니다. 곱셈의 경우 음수와 양수를 곱하면 음수가되며 두 음수를 곱하면 양수가됩니다. 임의의 값을 사용하여 이러한 속성이 모두 유지되는지 확인 테스트 값은 이러한 기능을 테스트하는 좋은 방법입니다. 일반적으로 둘 이상의 속성을 테스트해야하지만 모든 경우에 대해 예상되는 결과를 몰라도 함수의 올바른 동작을 함께 검증하는 유한 속성 집합을 식별 할 수 있습니다.

내가 본 속성 테스트에 대한 가장 좋은 소개 중 하나 는 F #에있는 것입니다. 구문이 기술의 설명을 이해하는 데 방해가되지 않기를 바랍니다.


답변

코드를 작성하고 결과가 “올바로”보이는지 확인하고 싶지만, 직관에 따라 좋은 생각이 아닙니다.

알고리즘이 어려운 경우 결과를 수동으로 쉽게 계산할 수 있도록 여러 가지 작업을 수행 할 수 있습니다.

  1. Excel을 사용하십시오. 일부 또는 모든 계산을 수행하는 스프레드 시트를 설정하십시오. 단계를 볼 수 있도록 간단하게 유지하십시오.

  2. 각각 자체 테스트를 통해 분석법을 더 작은 테스트 가능한 분석법으로 나눕니다. 작은 부품이 제대로 작동하면 다음 단계를 통해 수동으로 작업하십시오.

  3. 집계 특성을 사용하여 상태 점검을 수행하십시오. 예를 들어 확률 계산기가 있다고 가정합니다. 개별 결과가 무엇인지 모를 수도 있지만 결과가 모두 100 %가되어야한다는 것을 알고 있습니다.

  4. 무차별 대입 가능한 모든 결과를 생성하는 프로그램을 작성하고 알고리즘이 생성하는 것보다 나은 것이 없는지 확인하십시오.