결과를 예측하기 어려운 코드에 대한 단위 테스트를 어떻게 작성합니까?


124

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

이런 종류의 코드로 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
}

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


4
결과를 예측하기 어려운 간단한 함수 예제를 제공 할 수 있습니까?
Robert Harvey

62
FWIW 알고리즘을 테스트하지 않습니다. 아마 맞습니다. 구현을 테스트하고 있습니다. 손으로 운동하는 것은 종종 평행 구조로 좋습니다.
Kristian H


7
실행 시간이 여러 날 / 월인 경우와 같이 알고리즘을 합리적으로 단위 테스트 할 수없는 상황이 있습니다. NP 문제를 해결할 때 발생할 수 있습니다. 이러한 경우 코드가 올바른지 공식적으로 증명 하는 것이 더 적합 할 있습니다 .
Hulk

12
매우 까다로운 숫자 코드에서 본 것은 단위 테스트를 회귀 테스트로만 처리하는 것입니다. 함수를 작성하고 몇 가지 흥미로운 값으로 실행하고 수동으로 결과를 검증 한 다음 예상 결과에서 회귀를 포착하기 위해 단위 테스트를 작성하십시오. 코딩 공포? 다른 사람들의 생각이 궁금합니다.
Chuu

답변:


251

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

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

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


54
이것이 매우 좋은 조언이라고 생각하십시오. 이러한 종류의 단위 테스트를 작성하여 시작하십시오. 소프트웨어를 개발할 때 버그 나 정답을 찾으면 단위 테스트로 추가하십시오. 확실히 정답을 찾으면 어느 정도 똑같이하십시오. 시간이 지남에 따라 그들을 구축하고, 당신은 그들이 무엇을할지 모르고 시작하더라도 매우 완전한 단위 테스트를 할 것입니다 ...
Algy Taylor

21
어떤 경우에는 도움이 될 수있는 또 다른 것은 (아마도이 ​​기능은 아니지만) 역함수를 작성하고 연결될 때 입력과 출력이 동일한 지 테스트하는 것입니다.
Cyberspark

7
위생 검사는 종종 QuickCheck
jk

10
내가 권장하는 다른 테스트 범주는 의도하지 않은 출력 변경을 확인하기위한 몇 가지입니다. 의도하지 않은 출력 중립적 변경으로 의도 된 것이 알고리즘 동작에 영향을 미쳤다는 플래그를 지정하여 유지 관리자를 돕는 것이기 때문에 코드 자체를 사용하여 예상 결과를 생성하여 '속임수'할 수 있습니다.
Dan Neely

5
@iFlo 농담인지 확실하지 않지만 역의 반대는 이미 존재합니다. 테스트 실패가 역함수에서 문제가 될 수 있다는 것을 깨달을 가치가 있습니다.
lucidbrot

80

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

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


32
변성 관계 속성 기반 테스트 의 특정 예 . 일반적으로 다음과 같은 상황에 유용한 도구입니다.
Dannnno

38

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

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

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


6
그리고 기록을 위해 이러한 종류의 테스트는 목적에 따라 종종 "회귀 테스트"라고하며 기본적으로 모든 수정 / 리팩토링을위한 안전망입니다.
Pac0

21

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

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

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

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


2
비 결정적 알고리즘의 경우 고정 시퀀스 또는 불일치가 낮은 비 결정적 시리즈 (예 : Halton sequence
wondra

14
@PaintingInAir 알고리즘의 출력을 확인할 수 없다면 알고리즘 틀릴 수 있습니까?
WolfgangGroiss

5
Unless your code involves some random element여기서 트릭은 난수 생성기를 주입 된 종속성으로 만드는 것이므로 원하는 정확한 결과를 제공하는 수 생성기로 대체 할 수 있습니다. 따라서 생성 된 숫자를 입력 매개 변수로 계산하여 정확하게 다시 테스트 할 수 있습니다. not deterministic (i.e. it won't produce the same output given the same input)단위 테스트는 통제 된 상황 에서 시작해야 하므로 무작위 요소가있는 경우에만 결정적이지 않을 수 있습니다. 나는 여기서 다른 가능성을 생각할 수 없다.
Flater

3
@PaintingInAir : 또는 내 의견은 빠른 실행 또는 빠른 테스트 작성에 모두 적용됩니다. 단일 예제를 직접 계산하는 데 3 일이 걸리는 경우 (코드를 사용하지 않는 가장 빠른 방법을 사용한다고 가정) 3 일이 소요됩니다. 예상되는 테스트 결과를 실제 코드 자체를 기반으로하는 경우 테스트 자체가 손상됩니다. 그건 마치 if(x == x)무의미한 비교입니다. 두 개의 결과 ( 실제 : 코드에서 나옴; 예상 : 외부 지식에서 나옴)는 서로 독립적이어야합니다.
Flater

2
사양을 준수하지 않고 규정 준수 여부를 측정 할 수있는 경우 (예 : 임의의 분포 및 분산) 비정상적인 위험을 제거하기 위해 많은 샘플이 필요할 수 있습니다.
mckenzm

17

의견이 게시되어 업데이트

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

문제가 발생할 가능성이 가장 높은 상황이라고 생각하기 때문에 "알고리즘을 직접 작성했다면"상황에 대해 더 자세히 설명해 드리겠습니다. 특히 "A이면 B이면, 그렇지 않으면 C"예제가없는 상황에서 특히 그렇습니다. (ps 나는 downvoter가 아니다)
PaintingInAir

@PaintingInAir :하지만 상황에 따라 정교하게 설명 할 수 없습니다. 이 알고리즘을 작성하기로 결정한 경우 특정 기능을 제공하기 위해 수행 한 것입니다. 누가 그렇게하라고 했어요? 그들은 그들의 요청을 어떻게 묘사 했습니까? 특정 시나리오에서 필요한 일을 알려 주었습니까? (이 정보는 제가 대답에서 "분석"이라고 합니다.) 알고리즘을 생성하게 한 설명 은 알고리즘이 요청한대로 작동하는지 테스트하는 데 사용할 수 있습니다. 요컨대, 코드 /자가 생성 알고리즘 이외의 것을 사용할 수 있습니다.
Flater

2
@PaintingInAir : 고객, 분석가 및 개발자를 긴밀하게 연결하는 것은 위험합니다. 문제의 정의 정의 와 같은 필수 단계를 건너 뛰기 쉽기 때문에 . 나는 그것이 당신이하고있는 일이라고 믿습니다. 알고리즘이 올바르게 구현되었는지 여부가 아니라 알고리즘 의 정확성 을 테스트하려는 것 같습니다 . 그러나 그렇게하는 것이 아닙니다. 구현 테스트는 단위 테스트를 사용하여 수행 할 수 있습니다. 알고리즘 자체를 테스트하는 문제이다 사용하여 그 결과를 검사 사실 당신 (테스트) 응용 프로그램과 - (이 같은이 실제 시험은 당신의 코드베이스의 범위를 벗어 해야한다 ).
Flater

4
이 답변은 이미 엄청납니다. 원본 콘텐츠를 재구성하지 않고 새 답변에 통합 할 수 있도록 원본 콘텐츠를 재구성하는 방법을 찾는 것이 좋습니다.
jpmc26

7
또한, 나는 당신의 전제에 동의하지 않습니다. 테스트는 사양에 따라 코드가 잘못된 출력을 생성하는 시점을 밝혀 낼 수 있으며 반드시 밝혀야합니다. 알려진 일부 테스트 사례에 대한 출력의 유효성을 검사하는 테스트에 유효합니다. 또한 요리사는 유효한 버거 성분으로 "손 비누"를 받아들이는 것보다 더 잘 알고 있어야하며, 고용주는 요리사가 어떤 성분을 사용할 수 있는지에 대해 확실히 교육했습니다.
jpmc26

9

속성 테스트

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

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

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


1
임의의 쿼트 (a, b, c)를 생성하고 (ab) (cd)가 (ac-ad)-(bc-bd)를 생성하는지 확인하는 것과 같이 예제 재 곱셈에 좀 더 구체적인 것을 추가하는 것이 좋습니다. 곱하기 연산은 상당히 깨져서 (음수는 음수로 양수입니다) 규칙을 유지하지만 분배 규칙은 특정 결과를 예측합니다.
supercat

4

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

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

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

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

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

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


3의 경우 반올림 오류를 허용하십시오. 총액이 100,000001 % 또는 유사하지만 정확하지는 않은 수치 일 수 있습니다.
Flater

2
나는 4에 대해 잘 모르겠습니다. 가능한 모든 입력 조합에 대해 최적의 결과를 생성 할 수 있다면 (확인 테스트에 사용) 본질적으로 이미 최적의 결과를 계산할 수 있으므로 테스트하려는 두 번째 코드가 필요하지 않습니다 . 이 시점에서 이미 작동하는 것으로 입증 된 기존 최적 결과 생성기를 사용하는 것이 좋습니다. (아직 작동하는 것으로 입증되지 않은 경우, 결과에 의존하여 테스트를 시작하여 사실을 확인할 수 없습니다).
Flater

6
@flater는 일반적으로 다른 요구 사항과 무차별 대치가 충족하지 않는 정확성을 가지고 있습니다. 예를 들어 성능.
Ewan

1
@flater 당신이 그것을 믿는다면 당신의 정렬, 최단 경로, 체스 엔진 등을 사용하는 것을 싫어합니다. 그러나 당신의 반올림 오류에서 ID는 완전히 도박 허용 하루 종일 카지노
Ewan

3
@flater 당신은 킹 폰 끝 게임에 도착했을 때 사임합니까? 전체 게임이 무차별 적으로 강요 될 수 있다고해서 개별적인 입장이 불가능하다는 의미는 아닙니다. 하나의 네트워크에 대한 가장 짧은 경로를 무차별 적으로 실행한다고해서 모든 네트워크에서 가장 짧은 경로를 알고있는 것은
Ewan

2

TL; DR

다른 답변에없는 조언은 "비교 테스트"섹션으로 이동하십시오.


시작

알고리즘에 의해 거부되어야 workPerDay하는 경우 (예 : 0 또는 음수 )와 사소한 경우 (예 : 빈 tasks배열) 를 테스트하여 시작하십시오 .

그런 다음 가장 간단한 사례를 먼저 테스트하려고합니다. 를 들어 tasks입력, 우리는 서로 다른 길이를 테스트해야합니다; 0, 1 및 2 요소를 테스트하기에 충분해야합니다 (2는이 테스트의 "다수"범주에 속함).

정신적으로 계산할 수있는 입력을 찾을 수 있다면 좋은 시작입니다. 필자가 때때로 사용하는 기술은 원하는 결과에서 시작하여 (사양에서) 해당 결과를 생성해야하는 입력으로 되돌아가는 것입니다.

비교 테스트

때로는 출력과 입력의 관계가 명확하지 않지만 한 입력이 변경 될 때 다른 출력간에 예측 가능한 관계 가 있습니다. 예제를 올바르게 이해했다면 다른 입력을 변경하지 않고 작업을 추가해도 시간에 수행되는 작업의 비율이 증가하지 않으므로 추가 작업없이 한 번 및 한 번만 함수를 두 번 호출하는 테스트를 만들 수 있습니다 -두 결과 사이의 불평등을 주장합니다.

폴백

때로는 사양에 해당하는 단계로 손으로 계산 한 결과를 보여주는 긴 의견에 의지해야했습니다 (이러한 의견은 일반적으로 테스트 사례보다 깁니다). 최악의 경우는 다른 언어 나 다른 환경에서 이전 구현과의 호환성을 유지해야하는 경우입니다. 때로는 테스트 데이터에 다음과 같은 레이블을 지정해야합니다 /* derived from v2.6 implementation on ARM system */. 만족 스럽지는 않지만 이식 할 때의 충실도 테스트 또는 단기 목발로 받아 들일 수 있습니다.

알림

테스트의 가장 중요한 특성은 가독성입니다. 입력 및 출력이 판독기에 불투명 한 경우 테스트의 값이 매우 낮지 만 판독기가 이들 간의 관계를 이해하는 데 도움이되는 경우 테스트는 두 가지 목적을 수행합니다.

부정확 한 결과 (예 : 부동 소수점)에는 적절한 "대략 같음"을 사용하는 것을 잊지 마십시오.

과도한 테스트를 피하십시오. 다른 테스트로는 도달 할 수없는 항목 (예 : 경계 값)을 다루는 경우에만 테스트를 추가하십시오.


2

이런 종류의 테스트하기 어려운 기능에는 특별한 것이 없습니다. 외부 인터페이스를 사용하는 코드 (예 : 사용자가 제어하지 않고 테스트 스위트에서 테스트 할 수없는 타사 애플리케이션의 REST API)를 사용하는 코드에도 동일하게 적용됩니다. 반환 값의 정확한 바이트 형식).

정상적인 입력에 대해 단순히 알고리즘을 실행하고 수행하는 작업을 확인하고 결과가 올바른지 확인하고 입력 및 결과를 테스트 사례로 캡슐화하는 것은 매우 유효한 방법입니다. 몇 가지 경우에이 작업을 수행하여 여러 샘플을 얻을 수 있습니다. 입력 매개 변수를 가능한 한 다르게 만드십시오. 외부 API 호출의 경우 실제 시스템에 대해 몇 번의 호출을 수행하고 도구를 사용하여 추적 한 다음 단위 테스트로 모의하여 프로그램이 어떻게 반응하는지 확인하십시오. 이는 몇 가지를 선택하는 것과 같습니다. 작업 계획 코드 실행, 직접 확인한 다음 테스트에서 결과를 하드 코딩합니다.

그런 다음 빈 사례 목록 (예 :)과 같은 최첨단 사례를 가져옵니다. 그런 것들.

테스트 스위트는 결과를 쉽게 예측할 수있는 방법만큼 좋지 않을 수 있습니다. 그러나 테스트 스위트 (또는 연기 테스트)가없는 것보다 여전히 100 % 더 좋습니다.

문제 경우, 비록 당신이 그것을 열심히 찾을 것입니다 결정 결과 여부 입니다 올바른, 그는 전혀 다른 문제입니다. 예를 들어, 임의로 큰 숫자가 소수인지 여부를 감지하는 방법이 있다고 가정하십시오. 임의의 숫자를 거의 던질 수 없으며 결과가 정확하면 "보임"만 할 수 있습니다 (머리 나 종이의 소수를 결정할 수 없다고 가정). 이 경우 실제로 할 수있는 일은 거의 없습니다. 알려진 결과 (예 : 큰 소수)를 얻거나 다른 알고리즘으로 기능을 구현해야합니다 (다른 팀일 수도 있습니다)-NASA는 좋아하는 것 같습니다 즉) 구현 중 하나라도 버그가있는 경우 적어도 버그가 동일한 잘못된 결과를 초래하지 않기를 바랍니다.

이것이 일반적인 경우라면 요구 사항 엔지니어와 열심히 대화해야합니다. 그들이 당신을 확인하기 쉬운 (또는 가능한 모든) 방식으로 요구 사항을 공식화 할 수 없다면, 언제 끝났는지 알 수 있습니까?


2

다른 답변도 좋으므로 지금까지 놓친 포인트를 맞추려고 노력할 것입니다.

SAR (Synthetic Aperture Radar)을 사용하여 이미지 처리를 수행하는 소프트웨어를 작성하고 철저히 테스트했습니다. 그것은 과학적 / 숫자 적 성격을 지니고 있습니다 (많은 기하학, 물리학, 수학이 있습니다).

몇 가지 팁 (일반 과학 / 숫자 테스트) :

1) 역수를 사용하십시오. 무엇의 fft[1,2,3,4,5]? 몰라. 무엇입니까 ifft(fft([1,2,3,4,5]))? 있어야합니다 [1,2,3,4,5](또는 그 가까이에 부동 소수점 오류가 발생할 수 있음). 2D 경우도 마찬가지입니다.

2) 알려진 어설 션을 사용하십시오. 결정자 함수를 작성하면 결정자가 임의의 100x100 행렬인지를 말하기가 어려울 수 있습니다. 그러나 ID 행렬의 결정 요인이 100x100 인 경우에도 1이라는 것을 알고 있습니다. 또한 함수는 (0의 100x100 전체와 같이) 비가역 행렬에서 0을 반환해야한다는 것을 알고 있습니다.

3) 정확한 어설 션 대신 거친 어설 션을 사용하십시오 . 나는 SAR 처리를 위해 이미지 사이에 매핑을 생성하는 타이 포인트를 생성 한 다음 이미지 사이에 워프를 수행하여 두 이미지를 등록하는 코드를 작성했습니다. 하위 픽셀 수준에서 등록 할 수 있습니다. 선험적으로, 그것은 말하기 어려운 것도 두 이미지의 등록이 어떻게 보이는지에 대한합니다. 어떻게 테스트 할 수 있습니까? 같은 것들:

EXPECT_TRUE(register(img1, img2).size() < min(img1.size(), img2.size()))

겹치는 부분에만 등록 할 수 있으므로 등록 된 이미지 가장 작은 이미지보다 작거나 같아야합니다.

scale = 255
EXPECT_PIXEL_EQ_WITH_TOLERANCE(reg(img, img), img, .05*scale)

자체적으로 등록 된 이미지는 자체에 근접해야하지만 알고리즘으로 인해 부동 소수점 오류보다 약간 더 많은 오류가 발생할 수 있으므로 각 픽셀이 픽셀이 취할 수있는 범위의 +/- 5 % 내에 있는지 확인하십시오. (0-255는 회색조이며 이미지 처리에서 일반적입니다). 결과는 최소한 입력과 크기가 같아야합니다.

당신은 심지어 연기 테스트를 할 수 있습니다 (즉, 호출하고 충돌하지 않는지 확인하십시오). 일반적으로이 기술은 테스트를 실행하기 전에 최종 결과를 (쉽게) 계산할 수없는 대규모 테스트에 더 좋습니다.

4) RNG에 난수 시드를 사용하거나 저장하십시오.

재현 가능해야합니다. 그러나 재현 가능한 실행을 얻는 유일한 방법은 난수 생성기에 특정 시드를 제공하는 것입니다. 때때로 무작위성 테스트는 가치가 있습니다. 무작위로 생성 된 퇴화 사례에서 발생하는 과학 코드의 버그에 대해 보았습니다. 복잡한 알고리즘에서는 퇴화 사례 무엇인지 알기가 어려울 수 있습니다). 항상 동일한 시드로 함수를 호출하는 대신 임의의 시드를 생성 한 다음 해당 시드를 사용하고 시드 값을 기록하십시오. 이렇게하면 모든 실행에 서로 다른 임의의 시드가 있지만 충돌이 발생하면 로그에 기록한 시드를 사용하여 결과를 다시 실행할 수 있습니다. 나는 실제로 이것을 실제로 사용했고 버그를 없애 버렸으므로 언급 할 것이라고 생각했습니다. 분명히 이것은 한 번만 발생했으며 항상 가치가있는 것은 아니라고 생각 하므로이 기술을 신중하게 사용하십시오. 그러나 동일한 시드를 가진 무작위는 항상 안전합니다. 단점 (항상 동일한 시드를 사용하는 것과는 대조적으로) : 테스트 실행을 기록해야합니다. 거꾸로 : 정확성과 버그 핵작.

당신의 특별한 경우

1) 빈 값 이 0 (알려진 assert)을 리턴 하는지 테스트하십시오 taskArray .

2) 등이 임의의 입력을 생성 task.time > 0 , task.due > 0, task.importance > 0 모든 task S를, 그 결과보다 큰 써트 0 (거친 어설 랜덤 입력) . 당신은 미쳐서 임의의 시드를 생성 할 필요가 없습니다. 알고리즘은 그것을 보장하기에 충분히 복잡하지 않습니다. 약 0의 기회가 있습니다. 테스트를 간단하게 유지하십시오.

3) 모든 s에 대해 테스트하면 결과는 (어설 션으로 알려짐)task.importance == 0 task 0

4) 다른 답변에 대해서도 언급했지만 특정 경우에 중요 할 수 있습니다 . 팀 외부의 사용자가 API를 사용하도록하는 경우 퇴화 사례를 테스트해야합니다. 예를 들어 인 경우 workPerDay == 0사용자에게 잘못된 입력을 알려주는 멋진 오류를 발생시켜야합니다. API를 작성하지 않고 본인과 팀만을위한 것이라면이 단계를 건너 뛰고 퇴화 사례로 호출을 거부 할 수 있습니다.

HTH.


1

알고리즘의 속성 기반 테스트를 위해 어설 션 테스트를 단위 테스트 스위트에 통합하십시오. 특정 출력을 확인하는 단위 테스트를 작성하는 것 외에도 기본 코드에서 어설 션 오류를 트리거하여 실패하도록 설계된 테스트를 작성하십시오.

많은 알고리즘은 알고리즘 단계 전체에서 특정 속성을 유지하는 데 대한 정확성 증명에 의존합니다. 함수의 출력을보고 이러한 속성을 현명하게 확인할 수 있다면 단위 테스트만으로도 속성을 테스트 할 수 있습니다. 그렇지 않으면 어설 션 기반 테스트를 통해 알고리즘에서 가정 할 때마다 구현이 속성을 유지하는지 테스트 할 수 있습니다.

어설 션 기반 테스트는 수치 적 불안정성과 같은 문제로 인한 알고리즘 결함, 코딩 버그 및 구현 실패를 노출시킵니다. 많은 언어에는 컴파일 타임 또는 코드가 해석되기 전에 어설 션을 제거하는 메커니즘이있어 프로덕션 모드에서 실행될 때 어설 션에 성능 저하가 발생하지 않습니다. 코드가 단위 테스트를 통과했지만 실제 사례에서 실패하면 어설 션을 디버깅 도구로 다시 설정할 수 있습니다.


1

다른 답변 중 일부는 매우 좋습니다.

  • 테스트베이스, 엣지 및 코너 케이스
  • 위생 검사 수행
  • 비교 테스트 수행

... 나는 몇 가지 다른 전술을 추가 할 것입니다 :

  • 문제를 분해하십시오.
  • 코드 외부에서 알고리즘을 증명하십시오.
  • [외부 적으로 검증 된] 알고리즘이 설계된대로 구현되었는지 테스트하십시오.

분해를 통해 알고리즘의 구성 요소가 예상 한대로 작동하도록 할 수 있습니다. 또한 "양호한"분해를 통해 서로 잘 접착되도록 할 수 있습니다. 분해가 일반화하고 범위 알고리즘을 단순화 할 수 철저한 테스트를 작성하는 것이 충분히 손으로 (단순화 된 일반 알고리즘 (들)의) 결과를 예측합니다.

그 정도로 분해 할 수없는 경우, 귀하와 동료, 이해 관계자 및 고객을 만족시키기에 충분한 수단으로 코드 외부의 알고리즘을 증명하십시오. 그런 다음 구현이 디자인과 일치 함을 입증 할만큼 충분히 분해하십시오.


0

이것은 다소 이상적인 대답처럼 보이지만 다른 종류의 테스트를 식별하는 데 도움이됩니다.

엄격한 답변이 구현에 중요하다면 알고리즘을 설명하는 요구 사항에 예제와 예상 답변이 제공되어야합니다. 이러한 요구 사항을 그룹 검토해야하며 동일한 결과를 얻지 못하면 이유를 식별해야합니다.

분석가 및 구현 자의 역할을 수행하더라도 실제로 요구 사항을 작성하고 단위 테스트를 작성하기 훨씬 전에 검토해야하므로이 경우 예상 결과를 알고 그에 따라 테스트를 작성할 수 있습니다.

반면에, 이것이 비즈니스 로직의 일부가 아니거나 비즈니스 로직 응답을 지원하는 것으로 구현하는 부분 인 경우 결과를 확인하기 위해 테스트를 실행 한 다음 예상하도록 테스트를 수정하는 것이 좋습니다. 그 결과. 최종 결과는 이미 요구 사항과 비교하여 확인되었으므로 올바른 경우 해당 최종 결과를 제공하는 모든 코드는 수치 적으로 정확해야하며 그 시점에서 단위 테스트는 주어진 오류를 입증하는 것보다 에지 실패 사례 및 향후 리팩토링 변경을 감지하는 데 더 중요합니다 알고리즘이 올바른 결과를 생성합니다.


0

프로세스를 따르는 경우에는 완벽하게 수용 가능하다고 생각합니다.

  • 테스트 케이스 디자인
  • 답을 얻기 위해 소프트웨어를 사용하십시오
  • 직접 답을 확인하십시오
  • 회귀 테스트를 작성하여 향후 버전의 소프트웨어에서이 답변을 계속 제공합니다.

이는 첫 번째 원칙에서 직접 답변을 계산하는 것보다 직접 답변의 정확성을 확인하는 것이 더 쉬운 모든 상황에서 합리적인 접근 방식입니다.

인쇄 된 페이지를 렌더링하기 위해 소프트웨어를 작성하는 사람들을 알고 있으며 인쇄 된 페이지에 정확히 올바른 픽셀이 설정되어 있는지 확인하는 테스트를 받았습니다. 이 작업을 수행하는 유일한 방법은 페이지를 렌더링하는 코드를 작성하고보기 좋게 보이는지 확인한 다음 이후 릴리스에 대한 회귀 테스트로 결과를 캡처하는 것입니다.

특정 방법론이 테스트 사례를 먼저 작성하도록 권장하는 책을 읽었다 고해서 항상 그렇게해야한다는 의미는 아닙니다. 규칙이 깨질 것입니다.


0

다른 답변에는 이미 테스트 된 함수 외부에서 특정 결과를 확인할 수 없을 때의 테스트 모양에 대한 기술이 이미 있습니다 .

다른 답변에서 발견하지 않은 추가 작업은 어떤 방식으로 테스트를 자동 생성하는 것입니다.

  1. '임의의'입력
  2. 데이터 범위에 걸친 반복
  3. 경계 세트에서 테스트 케이스 구성
  4. 모든것 위에.

예를 들어, 함수가 각각 허용 된 입력 범위 [-1,1]의 3 개의 매개 변수를 사용하는 경우 각 매개 변수 {-2, -1.01, -1, -0.99, -0.5, -0.01, 0,0.01의 모든 조합을 테스트하십시오. , 0.5,0.99,1,1.01,2, (-1,1)에서 좀 더 임의}

한마디로 : 품질이 좋지 않은 경우 수량에 따라 보조금을 지급 할 수 있습니다.

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