주제

소개 페이지 맨 위

"개발자 테스트" 문구는 소프트웨어 개발자가 가장 적절하게 수행하는 테스트 활동을 범주화하는 데 사용됩니다. 또한 이러한 활동으로 생성된 결과물도 포함됩니다. 개발자 테스트에는 일반적으로 단위 테스트, 대다수의 통합 테스트, 시스템 테스트로 종종 언급되는 것의 범주에 대한 작업이 포함합니다. 개발자 테스트는 보통 구현 규칙의 활동과 연관되어 있지만 분석 및 설계 규칙의 활동과도 관계가 있습니다.

"전체론적" 방식으로 개발자 테스트를 생각해보면 전통적으로 사용해온 보다 "원자론적인" 방법과 연관된 일부 위험을 완화시켜줍니다. 전통적인 개발자 테스트 방법에서 기본적으로 모든 단위가 독립적으로 작동하는지 평가하는 데 초점을 두고 있습니다. 개발 라이프사이클 후반에 개발 작업이 완료될 수록 통합 단위는 작업 중인 서브시스템 또는 시스템으로 모아지고 이 설정에서 처음으로 테스트됩니다.

이 방법에는 수많은 약점이 있습니다. 먼저 통합 단위 및 이후 서브시스템에 대한 단계적 테스트 방법을 장려하기 때문에 이러한 테스트 중에 식별된 오류는 종종 너무 늦게 발견됩니다. 늦게 발견하게 되면 정정 조치를 취할 수 없거나 정정하기 위한 많은 재작업이 요구됩니다. 이 재작업에는 비용이 많이 들고 다른 분야의 개선사항을 손상시킵니다. 이것은 프로젝트의 실패 또는 포기의 위험성을 증가시킵니다.

두 번째로 단위, 통합 및 시스템 테스트 간에 엄격한 경계를 만들면 경계에 걸쳐진 오류가 아무에게도 발견되지 않을 확률이 높아집니다. 이러한 테스트 유형에 대한 책임이 별도의 팀에게 지정되면 위험은 더욱 심화됩니다.

RUP에서 권장되는 개발자 테스트 양식은 개발자가 지정된 시점에 가장 가치 있고 적절한 테스트에만 초점을 맞출 수 있게 합니다. 단일 반복 범위 내에서조차 일반적으로 별도의 테스트 그룹에 이양하는 추가 오버헤드 없이 개발자가 자신의 코드에 있는 가능한 많은 결함을 발견하고 정정하는 것이 보다 효과적입니다. 이러한 오류가 독립 단위, 통합 단위 또는 의미 있는 일반 사용자 시나리오 내에서 작동되는 통합 단위에 있는지 상관없이 가장 중요한 소프트웨어 오류를 일찍 발견하는 것이 원하는 결과입니다.

개발자 테스트로 시작할 때 빠지기 쉬운 함정 페이지 맨 위

테스트 작업을 보다 완전하게 수행하려고 시도하는 많은 개발자들은 오래지 않아 그 노력을 포기하게 됩니다. 쉽지 않다는 것을 알게 됩니다. 또한 개발자 테스트를 잘 시작한 일부 개발자들도 결국은 포기하게 될 어려운 테스트 도구를 만들었다는 사실을 발견하게 됩니다.

이 페이지에서는 첫 번째 관문을 극복하고 유지보수 함정을 비켜간 테스트 도구를 만들수 있는 몇 가지 가이드라인을 제공합니다. 자세한 정보는 가이드라인: 자동화된 테스트 도구 유지보수를 참조하십시오.

기대 구축 페이지 맨 위

개발자 테스트의 중요함을 아는 사람들은 수행합니다. 개발자 테스트를 하기 어려운 일로 보는 사람들은 이를 피하려고 합니다. 이것은 대부분 업계의 대다수 개발자들의 특성이며 역사적으로 성공한 적이 없는 부끄러운 규칙의 부족으로 치부합니다. 따라서, 개발자로서 테스트는 가치 있는 일로 예상하고 가치 있도록 수행해야 합니다.

이상적인 개발자 테스트에는 매우 꽉 짜여진 수정 테스트 루프가 뒤따릅니다. 클래스에 새 메소드를 추가하는 것과 같이 제품을 변경하게 되면 즉시 테스트를 재실행해야 합니다. 테스트가 중단되면 원인이 되는 코드를 정확히 알 수 있습니다. 쉽고 꾸준하게 개발이 진행되는 것은 개발자 테스트의 가장 큰 보람입니다. 긴 디버깅 세션은 예외적이어야 합니다.

한 클래스에서 수행된 변경사항이 다른 클래스에 있는 것을 중단시키는 것은 보기 드문 사실이 아니기 때문에 변경된 클래스의 테스트 뿐만 아니라 많은 테스트를 재실행해야 합니다. 이상적으로는, 컴포넌트에 대해 전체 테스트 도구를 시간 당 여러번 재실행합니다. 중요한 변경을 수행할 때마다 도구를 재실행하고 결과를 관찰하며 다음 변경으로 진행하거나 마지막 변경을 수정합니다. 빠른 피드백을 가능하게 하려면 노력이 필요할 수 있습니다.

테스트 자동화 페이지 맨 위

테스트 실행은 종종 테스트가 수동인 경우 실용적이지 않습니다. 일부 컴포넌트의 경우 자동화된 테스트가 쉽습니다. 한 예로는 메모리내 데이터베이스가 있습니다. 이 데이터베이스는 API를 통해 클라이언트와 통신하고 그 외부에는 다른 인터페이스가 없습니다. 이에 대한 테스트는 다음과 유사합니다.

/* Check that elements can be added at most once. */
// Setup
Database db = new Database();
db.add("key1", "value1");
// Test
boolean result = db.add("key1", "another value");
expect(result == false);

테스트는 오직 한 가지 점에서(API 호출 결과를 믿는 대신 확인한다는 점에서) 일반 클라이언트 코드와 다릅니다. API가 클라이언트 코드를 작성하기 쉽게 만드는 경우 테스트 코드도 작성하기 쉽게 됩니다. 테스트 코드가 작성하기 쉽지 않은 경우 API를 향상시킬 수 있는 경고를 이전에 받아본 적이 있는 것입니다. 따라서 테스트 우선 설계는 중요한 위험을 미리 처리하는 Rational Unified Process의 초점과 일치합니다.

컴포넌트가 외부 세계와 단단히 연결되어 있을수록 테스트하기는 어렵습니다. 그래픽 사용자 인터페이스 및 백엔드 컴포넌트의 두 가지 일반 사례가 있습니다.

그래픽 사용자 인터페이스

위 예에서 데이터베이스가 사용자 인터페이스 객체로부터 콜백을 통해 데이터를 수신했다고 가정합시다. 콜백은 사용자가 일부 텍스트 필드를 채우고 단추를 누르면 호출됩니다. 수동으로 필드를 패우고 단추를 눌러 이를 테스트하게 되면 일정 시간에 많은 것을 수행할 수 없습니다. 대개 단추 "누르기"를 코드로 작성하는 프로그램적인 제어 하에서 입력을 전달하는 방법을 배열해야 합니다.

단추를 누르면 컴포넌트의 일부 코드가 실행됩니다. 대체로 해당 코드는 일부 사용자 인터페이스 객체의 상태를 변화시킵니다. 따라서 이러한 객체를 조회하는 방법도 프로그램으로 준비해야 합니다.

백엔드 컴포넌트

테스트 중인 컴포넌트가 데이터베이스를 구현하지 않는다고 가정합시다. 대신 실제 디스크 상의 데이터베이스 주위에 랩퍼를 구현합니다. 해당 실제 데이터베이스에 대해 테스트하는 것은 어려울 수 있습니다. 설치 및 구성이 어려울 수 있습니다. 이에 대한 라이센스에도 비용이 많이 들 수 있습니다. 데이터베이스는 테스트 속도를 늦추어 자주 실행하지 않게 될 수 있습니다. 이러한 경우 테스트를 지원하기에 충분한 보다 단순한 컴포넌트로 데이터베이스를 "잘라내는" 것이 바람직합니다.

스텁은 해당 컴포넌트가 대화하는 컴포넌트가 아직 준비되어 있지 않은 경우에도 유용합니다. 테스트가 다른 누군가의 코드에 의해 지연되는 것을 원하지는 않을 것입니다.

자세한 정보는 개념: 스텁을 참조하십시오.

자체 툴 작성 금지 페이지 맨 위

개발자 테스트는 매우 간단한 것처럼 보입니다. 몇 가지 객체를 설정하고 API를 통해 호출하며 결과를 확인하고 결과가 예상과 다르면 테스트 실패를 공표합니다. 또한 테스트를 개별적으로 실행하거나 전체 도구로 실행할 수 있도록 테스트를 묶는 것이 편리합니다. 이러한 요구사항을 지원하는 툴을 테스트 프레임워크라고 합니다.

개발자 테스트는 간단하고 테스트 프레임워크의 요구사항은 복잡하지 않습니다. 그러나 자체 테스트 프레임워크를 작성하게 되면 예상보다 훨씬 많은 시간을 프레임워크를 수선하는 데 보내게 됩니다. 상업적 및 개방 소스로 사용 가능한 많은 테스트 프레임워크가 있어 이들 중 한 가지를 사용하게 됩니다.

지원 코드 작성 페이지 맨 위

테스트 코드는 반복적이기 쉽습니다. 다음과 같은 일련의 코드를 보는 것이 일반적입니다.

// null name not allowed
retval = o.createName(""); 
expect(retval == null);
// leading spaces not allowed
retval = o.createName(" l"); 
expect(retval == null);
// trailing spaces not allowed
retval = o.createName("name "); 
expect(retval == null);
// first character may not be numeric
retval = o.createName("5allpha"); 
expect(retval == null);

이 코드는 한 검사를 복사하고 붙여넣은 후 편집하여 다른 검사를 작성합니다.

여기에 위험이 두 배가 됩니다. 인터페이스가 변경되면 많은 편집을 수행해야 합니다. (보다 복잡한 상황에서 단순한 전체 대체 작업으로는 충분하지 않습니다.) 또한 코드가 복잡한 경우 모든 텍스트에서 테스트 목적을 상실할 수도 있습니다.

자체 반복을 발견하게 되면 반복되는 사항을 지원 코드로 뽑아내는 것을 신중히 고려하십시오. 위 코드는 단순한 예이지만 다음과 같이 작성하면 보다 읽기 쉽고 관리하기 좋습니다.

void expectNameRejected(MyClass o, String s) {
    Object retval = o.createName(s);
    expect(retval == null);
}
...
// null name not allowed
expectNameRejected(o, ""); 
// leading spaces not allowed.
expectNameRejected(o, " l"); 
// trailing spaces not allowed.
expectNameRejected(o, "name "); 
// first character may not be numeric.
expectNameRejected(o, "5alpha"); 

테스트를 작성하는 개발자는 주로 너무 많은 복사 및 붙여넣기 작업에 치우치게 됩니다. 자신의 이러한 경향이 의심되는 경우 의식적으로 다른 방식으로 작업해야 합니다. 코드의 모든 중복되는 텍스트를 없애는 것이 해결 방법입니다.

테스트 우선 작성 페이지 맨 위

코드 작업 후에 테스트를 작성하는 것은 힘든 일입니다. 수행하여 완료하고 다음 단계로 나가는 것이 좋습니다. 코드 이전에 테스트를 작성하면 긍정적인 피드백 루프의 테스트 부분이 만들어집니다. 보다 많은 코드를 구현함에 따라 최종적으로 모든 테스트를 통과할 때까지 통과하는 테스트를 많이 보게 되고 완료하게 됩니다. 먼저 테스트를 작성하는 사람들이 성공하기 쉽고 시간이 적게 걸립니다. 테스트를 먼저 시작하는데 대한 자세한 정보는 개념: 테스트 우선 설계를 참조하십시오.

이해 가능한 테스트로 유지 페이지 맨 위

이후에 다른 사람이 테스트를 수정할 수 있다는 것을 예상해야 합니다. 일반적 상황은 반복 후반에 컴포넌트 작동에 대한 변경이 요구되는 경우입니다. 간단한 예로 다음과 유사한 제곱근 방법을 선언한 컴포넌트를 가정합시다.

double sqrt(double x);

이 버전에서 음수 인수는 sqrt가 NaN("not a number"- 출처: IEEE 754-1985 Standard for Binary Floating-Point Arithmetic)을 리턴시킵니다. 새 반복에서 제곱근 방법은 음수를 수용하고 복수 결과를 리턴합니다.

Complex sqrt(double x);

sqrt에 대한 이전 테스트는 변경되어야 합니다. 이것은 이전 수행 내용을 이해하고 새 sqrt에서 작동하도록 갱신한다는 것을 의미합니다. 테스트를 갱신할 때 버그 발견 기능을 손상시키지 않도록 주의해야 합니다. 다음은 발생 가능한 예입니다.

void testSQRT () {
	//  Update these tests for Complex 
	// when I have time -- bem
	/*
		double result = sqrt(0.0);
		...
	*/
}

기타 방법은 보다 이해하기 어려울 수 있습니다. 테스트가 변경되어 테스트는 실제로 실행되지만 더 이상 이전에 테스트하려고 했던 사항을 테스트하지 않습니다. 결과적으로, 여러 번 반복을 통해 테스트 도구는 쇠약해져서 버그를 파악할 수 없습니다. 이것을 종종 "테스트 도구 퇴화"라고 합니다. 퇴화된 도구는 지속할 가치가 없기 때문에 버립니다.

테스트가 구현하는 테스트 아이디어가 분명하지 않는한 테스트의 버그 발견 기능을 유지할 수 없습니다. 테스트 코드는 종종 제품 코드보다 그 뒤의 "이유"를 이해하기 어렵지만 설명 처리합니다.

테스트 도구 퇴화는 간접 테스트에서보다 sqrt에 대한 직접 테스트에서는 발생 가능성이 적습니다. sqrt를 호출하는 코드가 있게 됩니다. 해당 코드는 테스트를 갖게 됩니다. sqrt가 변경되면 이러한 테스트 중 일부가 실패합니다. sqrt를 변경하는 개인은 이러한 테스트도 변경해야 합니다. 테스트에 익숙하지 않거나 변경 관계가 덜 분명하기 때문에 통과하는 프로세스에서 취약할 수 있습니다.

테스트에 대한 지원 코드를 작성할 때(위에서 권장한 대로) 주의하십시오. 지원 코드는 이를 사용하는 테스트 목적이 모호하지 않고 분명해야 합니다. 객체 지향 프로그램에 관한 공통적인 불만사항은 모든 것을 수행할 수 있는 위치가 없다는 것입니다. 한 가지 방법을 보고 있는 경우 발견하는 모든 것은 어딘가 해당 작업을 향하고 있게 됩니다. 이러한 구조는 장점이 있지만 새로운 담당자가 코드를 이해하기는 더 어렵게 됩니다. 그들이 노력하지 않는 한 수행한 변경사항은 틀리기 쉽거나 코드를 너무 복잡하고 허술하게 만들기 쉽습니다. 이후 유지보수자가 주의를 덜 기울이는 경우를 제외하고 테스트 코드에서도 동일합니다. 이해 가능한 테스트를 작성하여 문제점을 예방해야 합니다.

제품 구조에 테스트 구조 일치 페이지 맨 위

누군가 컴포넌트를 상속했다고 가정합시다. 이 경우 일부를 변경해야 합니다. 새로운 설계에 도움이 되는 이전 테스트를 알아보고자 할 수 있습니다. 코드를 작성하기 전에 이전 테스트를 갱신하려고 합니다(테스트 우선 설계).

이러한 모든 좋은 의도는 적절한 테스트를 발견할 수 없는 경우 보류됩니다. 수행할 사항은 변경을 수행하고 실패한 테스트 내용을 확인한 후 수정하는 것입니다. 이것은 테스트 도구 퇴화의 한 원인이 됩니다.

이러한 이유로 테스트 도구를 잘 구조화하고 테스트 위치를 제품 구조로부터 예측 가능하게 하는 것이 중요합니다. 가장 일반적으로 개발자는 제품 클래스 당 하나의 테스트 클래스를 사용하여 병렬 계층 구조로 테스트를 배치합니다. 따라서 Log라는 클래스를 변경하는 경우 테스트 클래스는 TestLog이고 소스 파일의 위치를 알 수 있습니다.

테스트 캡슐화 위반 페이지 맨 위

클라이언트 코드가 사용하는 동일한 인터페이스를 통해 정확히 클라이언트 코드가 수행하는 것처럼 컴포넌트와 상호작용하도록 테스트를 제한할 수 있습니다. 그러나 여기에는 단점이 있습니다. 다음과 같이 이중 링크 목록을 유지하는 간단한 클래스를 테스트하고 있다고 가정합시다.

샘플 이중 링크 목록 이미지

그림1: 이중 링크 목록

특히 DoublyLinkedList.insertBefore(Object existing, Object newObject) 메소드를 테스트하는 중입니다. 테스트 중 하나에서 목록 중간에 한 요소를 삽입한 후 성공적인 삽입 여부를 확인하려고 합니다. 테스트는 위 목록을 사용하여 다음 갱신된 목록을 작성합니다.

삽입된 항목이 있는 샘플 이중 링크 목록 이미지

그림2: 이중 링크 목록 - 삽입된 항목

다음과 같이 목록의 정확성을 검사합니다.

// the list is now one longer. 
expect(list.size()==3);
// the new element is in the correct position
expect(list.get(1)==m);
// check that other elements are still there.
expect(list.get(0)==a);
expect(list.get(2)==z);

이것으로 충분한 것같지만 그렇지 않습니다. 목록 구현이 올바르지 않고 역방향 포인터가 제대로 설정되지 않았다고 가정합시다. 즉 갱신된 목록이 실제로 다음과 같아 보인다고 가정합시다.

구현 결함이 있는 샘플 이중 링크 목록 이미지

그림3: 이중 링크 목록 - 구현 결함

DoublyLinkedList.get(int index)가 목록의 시작에서 끝까지 걸쳐 있는 경우 테스트는 이 결함을 놓치게 됩니다. 클래스가 elementBeforeelementAfter 메소드를 제공하는 경우 이러한 결함 검사는 수월합니다.

// Check that links were all updated
expect(list.elementAfter(a)==m);
expect(list.elementAfter(m)==z);
expect(list.elementBefore(z)==m); //this will fail
expect(list.elementBefore(m)==a);

그러나 이러한 메소드를 제공하지 않는 경우는 어떠합니까? 의심되는 결함이 존재하는 경우 실패하는 메소드 호출의 보다 정교한 순서를 고안할 수 있습니다. 예를 들어, 다음이 유효합니다.

// Check whether back-link from Z is correct.
list.insertBefore(z, x);
// If it was incorrectly not updated, X will have 
// been inserted just after A.
expect(list.get(1)==m); 

그러나 이러한 테스트는 작성하는 데 보다 많은 작업이 필요하고 유지보수하기가 매우 어렵습니다. (적절한 설명을 작성하지 않는 한 테스트 수행 이유 및 수행 내용이 분명치 않게 됩니다.) 여기에는 두 가지 솔루션이 있습니다.

  1. elementBeforeelementAfter 메소드를 공용 인터페이스에 추가하십시오. 그러나 모든 사람이 효과적으로 구현할 수 있으나 이후 변경은 보다 어려워집니다.
  2. 테스트를 "자세히 볼 수 있게 하여" 포인터를 직접 확인하십시오.

DoublyLinkedList와 같은 간단한 클래스에도 특히 제품에서 발생하는 보다 복잡한 클래스의 경우 후자가 일반적으로 최적의 솔루션입니다.

일반적으로 테스트는 테스트하는 클래스와 동일한 패키지에 있습니다. 보호되거나 손쉽게 접근할 수 있는 권한이 지정되어 있습니다.

특징적인 테스트 설계 실수 페이지 맨 위

각 테스트는 컴포넌트를 작용시키고 올바른 결과를 검사합니다. 테스트 설계(사용하는 정보 및 정확성을 검사하는 방법)는 결함을 표시하는 데 유용하거나 우연하게 결함을 숨길 수 있습니다. 다음은 몇 가지 특징적인 테스트 설계 실수입니다.

미리 예상 결과를 지정하는 데 실패 페이지 맨 위

XML을 HTML로 변환하는 컴포넌트를 테스트하고 있다고 가정합시다. 일부 샘플 XML을 사용하여 변환을 실행한 후 브라우저에서 그 결과를 보려고 합니다. 화면이 올바르게 보이는 경우 공식 예상 결과로 저장하여 HTML을 "보존합니다". 그 이후 테스트는 변환의 실제 출력을 예상 결과와 비교합니다.

이것은 위험한 습관입니다. 심지어 속임수를 쓰는 컴퓨터 사용자가 컴퓨터가 수행하는 내용을 믿게 하는 데 사용됩니다. 화면 겉모습의 실수를 간과하기 쉽습니다. (브라우저가 잘못 형식화된 HTML에 매우 관대하는 것을 언급하는 것이 아님) 해당 잘못된 HTML을 공식 예상 결과로 만들면 테스트가 결코 문제점을 발견할 수 없게 하는 것입니다.

직접 HTML을 보면서 이중 검사를 하는 것이 덜 위험하지만 여전히 위험성은 있습니다. 출력이 복잡하기 때문에 오류를 간과하기 쉽습니다. 예상 출력을 미리 손으로 작성하는 경우 보다 많은 결함을 발견하게 됩니다.

백그라운드 검사 실패 페이지 맨 위

테스트는 보통 변경되어야 할 사항이 변경되었는지 검사하지만, 작성자는 남겨두어야 할 부분을 남겨두었는지 검사하는 것을 잊기 쉽습니다. 예를 들어, 프로그램이 파일의 처음 100개 레코드를 변경해야 한다고 가정합시다. 101번째 레코드가 변경되지 않았는지 검사하는 것이 좋은 방법일 수 있습니다.

이론적으로 "백그라운드"(전체 파일 시스템, 모든 메모리, 네트워크를 통해 도달 가능한 모든 것)에서는 남겨진 것에 대해 확인하지 않습니다. 실제로 검사해야 하는 내용을 주의깊게 선택해야 합니다. 해당 선택을 하는 것이 중요합니다.

지속성 검사 실패 페이지 맨 위

컴포넌트가 변경 사실을 알렸다는 이유만으로 실제로 데이터베이스에 확약되었음을 의미하지는 않습니다. 다른 경로를 통해 데이터베이스를 검사해야 합니다.

다양성 추가 실패 페이지 맨 위

테스트가 데이터베이스 레코드의 세 필드의 결과를 검사하도록 설계되었을 수 있지만 테스트 실행을 위해서는 다른 많은 필드를 채워야 합니다. 테스터는 이러한 "관계 없는" 필드에 동일한 값을 계속하여 재사용합니다. 예를 들어, 항상 텍스트 필드에는 연인의 이름을 사용하고 숫자 필드에는 999를 사용합니다.

문제점은 가끔 문제가 되어서는 안되는 일들이 실제 문제가 된다는 것입니다. 때때로 일부 모호한 입력 조합에 의한 버그가 있습니다. 항상 동일한 입력을 사용하는 경우 이러한 버그를 찾을 수 없게 됩니다. 지속적으로 입력을 다양화하면 버그를 찾을 수 있습니다. 999와 다른 숫자를 사용하거나 다른 사람의 이름을 사용해도 비용은 거의 들지 않습니다. 테스트에 다양한 값을 사용하는 경우 거의 비용이 들지 않으며 몇 가지 잠재적인 장점이 있습니다. (주: 현재 연인이 함께 일하는 경우 현재 연인의 이름 대신 이전 연인의 이름을 사용하는 것은 현명하지 못합니다.)

다음은 또 다른 장점입니다. 가능성 있는 한 가지 결함은 프로그램이 Y 필드를 사용했어야 하는 데 X 필드를 사용하는 것입니다. 두 필드가 모두 "Dawn"을 포함하는 경우 결함을 발견할 수 없습니다.

실질적인 데이터 사용 실패 페이지 맨 위

테스트에 꾸며낸 데이터를 사용하는 것은 일반적입니다. 이 데이터는 종종 비현실적으로 단순합니다. 예를 들어, 고객 이름이 "Mickey", "Snoopy", "Donald"일 수 있습니다. 해당 데이터는 실제 사용자가 입력하는 것과 다르기 때문에(예: 특징적으로 짧기 때문에) 실제 고객이 보게 되는 결함을 놓칠 수 있습니다. 예를 들어, 한 단어 이름은 코드가 공백을 포함한 이름을 처리하지 못한다는 사실을 발견할 수 없게 됩니다.

실질적인 데이터를 사용하기 위해 좀 더 노력을 기울이는 것이 현명합니다.

코드의 무위성 발견 실패 페이지 맨 위

데이터베이스 레코드를 0으로 초기화하고 레코드에 저장 중인 0으로 결과가 생성되어야 하는 계산을 실행한 후 레코드가 0인지 검사한다고 가정합시다. 테스트가 보여주는 것은 무엇입니까? 계산은 전혀 발생하지 않았을 수도 있습니다. 아무것도 저장되지 않았을 수 있지만 테스트는 이에 대해 알려줄 수 없습니다.

해당 예는 거의 발생하지 않을 수 있습니다. 그러나 동일한 실수가 미묘한 방식으로 나타날 수 있습니다. 예를 들어, 복잡한 설치 프로그램에 대한 테스트를 작성할 수 있습니다. 테스트는 성공적인 설치 이후 모든 임시 파일이 제거되었는지 검사하려고 합니다. 그러나 모든 설치 프로그램 옵션 때문에 해당 테스트에서 한 가지 특정 임시 파일이 작성되지 않았습니다. 당연히 그것은 프로그램이 제거하지 않은 것입니다.

코드의 잘못된 수행 발견 실패 페이지 맨 위

가끔씩 프로그램은 잘못된 이유로 올바른 일을 수행합니다. 사소한 예로 다음 코드를 생각해봅시다.

if (a < b && c) 
    return 2 * x;
else
    return x * x;

논리식이 틀리고 올바르지 않게 평가하고 잘못된 분기를 사용하는 테스트를 작성하였습니다. 불행하게도 해당 테스트에서 우연히 변수 X에 2 값이 있습니다. 따라서 잘못된 분기 결과가 올바른 분기를 제공한 결과와 동일하게 우연히 올바릅니다.

각 예상 결과에 대해 잘못된 이유로 해당 결과를 생성할 수 있는 그럴듯한 사항이 있는지 질문해야 합니다. 가끔 알 수 있습니다.



Rational Unified Process   2003.06.15