Test Run

확산 테스트

James McCaffrey

코드 샘플 다운로드

image: James McCaffrey 이달의 칼럼에서는 확산 테스트라는 소프트웨어 테스트 기법을 소개하겠습니다. 확산 테스트의 핵심 아이디어는 합격 결과가 나온 기존 테스트 사례에서 자동으로 새 테스트 사례 데이터를 생성하는 것이 가능한 경우가 있다는 것입니다.

확산 테스트는 대부분의 소프트웨어 테스트 시나리오에 적용 가능한 기법은 아니지만 적용 가능한 경우 테스트 성과를 크게 향상시킬 수 있습니다. 아마도 틈새 기법이기 때문이기도 하겠지만 필자의 경험에 비추어볼 때 확산 테스트는 모든 주요 테스트 기법 중에서 가장 적게 알려진 기법입니다.

확산 테스트의 예를 소개하기 전에 이 방법이 만들어진 이유를 설명하겠습니다. 하나의 테스트 사례는 일반적으로 테스트 사례 ID, 하나 이상의 입력 집합, 그리고 예상되는 결과로 구성됩니다. 예를 들어, 벡터 {001, 2, 3, 5}로 ID = 001, 입력 = 2 및 3, 그리고 예상 결과 = 5인 Sum 함수의 테스트 사례를 만들 수 있습니다. 테스트 사례 입력은 테스트 중인 시스템으로 전송되고 실제 결과가 생성되면 실제 결과와 예상 결과를 비교하여 테스트 사례 성공/실패 결과를 결정합니다.

많은 소프트웨어 테스트 상황에서 테스트 사례의 예상 결과 부분을 결정하기가 어렵고 시간이 많이 걸리는 경우가 많습니다. 예를 들어 비율인 두 입력의 조화평균을 계산하는 기본적인 수학 함수를 테스트한다고 가정해 보겠습니다. 시속 30.0Km(kph)와 시속 60.0Km(kph)의 평균은 (30.0 + 60.0) / 2 = 시속 45.0Km(kph)가 아니라 30.0과 60.0의 조화 평균인 1 / ((1/30.0 + 1/60.0) / 2) = 시속 40.0Km(kph)입니다. 이 함수에 사용할 수백 개의 예상 결과를 생성하는 일은 지루할 뿐 아니라 시간이 많이 걸리고 오류가 생길 가능성도 높습니다.

테스트 사례의 예상 결과를 결정하기 어려운 문제는 소프트웨어 테스트의 기본 개념이기도 하며 테스트 오라클 문제라고도 합니다. 실제로 테스트 사례를 자동으로 결정할 수 있는 기법을 찾아내는 것은 소프트웨어 테스트의 성배 중 하나입니다. 확산 테스트의 동기는 어떤 방법으로든 새 테스트 사례 데이터를 자동으로 생성할 수 있다면 테스트 프로세스의 시간이 많이 소모되는 부분을 가속화하고 시스템을 보다 철저하게 테스트할 수 있다는 것입니다.

확산 테스트로 테스트 사례 데이터를 자동으로 생성한다는 개념은 기본적으로 훌륭하지만 어떻게 작동하는 것일까요? 확산 테스트를 설명하는 가장 좋은 방법은 예를 살펴보는 것입니다. 그림 1을 살펴보시기 바랍니다.

image: Diffusion Testing Demo

그림 1 확산 테스트 데모

여기에서는 순서에 관계없이 n개의 항목에서 k를 선택하는 방법의 수를 반환하는 Choose(n,k) 함수를 테스트합니다. 이 간소화된 예에는 세 개의 기존 테스트 사례가 있습니다. 첫째 테스트 사례는 입력은 n = 8 및 k = 3이고 예상 결과는 56입니다. 테스트 장비로 첫째 테스트 사례를 실행하고 합격 결과가 나오면 확산 테스트를 사용하여 입력이 n = 9, k = 3이고 예상 결과가 84인 새 테스트 사례를 자동으로 생성할 수 있습니다. 멋지지 않습니까? 테스트 사례 002의 경우에는 실패 결과가 나오기 때문에 새 확산 테스트 결과를 생성하지 않았습니다.

그렇다면 어떻게 기존 테스트 사례에서 새 테스트 사례를 생성할 수 있을까요? Choose(n,k) 함수의 경우, 수학적으로 Choose(n+1,k) = Choose(n,k) * (n+1) / (n-k+1) 관계가 성립합니다. 다른 말로 하면 새 입력과 기존 반환 값 사이에 알려진 관계가 있습니다. 그림 2에는 기존 테스트 사례에서 확산된 테스트 사례를 생성하기 위해 사용한 함수가 나옵니다. 출력을 생성하는 전체 프로그램은 그림 1에 있으며 code.msdn.microsoft.com/mag201103TestRun에서 받을 수 있습니다.

그림 2 새 테스트 사례 생성

static string CreateDiffusedTestCase(string existingTestCase)
{
  // Assumes input format is CaseID:N:K:Expected
  string[] tokens = existingTestCase.Split(':');
  string oldTestCase = tokens[0];
  int oldN = int.Parse(tokens[1]);
  int oldK = int.Parse(tokens[2]);
  long oldExpected = long.Parse(tokens[3]);
  string newTestCase = oldTestCase + "-diffused";
  int newN = oldN + 1;
  int newK = oldK;
  long newExpected = (oldExpected * (oldN + 1)) / (oldN - oldK + 1);
  return newTestCase + ":" + newN + ":" + newK + ":" + newExpected;
}

몇 가지 다른 예를 살펴보면 이해하는 데 도움이 될 것입니다. 삼각함수 사인과 코사인을 계산하는 함수를 테스트한다고 가정해 보겠습니다. sin 2t = 2 * sin t * cos t임을 기억하는 분들이 있을 것입니다. 즉, 어떤 입력에 대한 사인 및 코사인에 합격 결과가 나오는 테스트 사례가 있다면 확산 테스트로 사인 함수에 대한 새 테스트 사례를 파생시킬 수 있습니다.

확산 테스트는 마법은 아닙니다. 일종의 제품 ID를 받고 SQL 데이터베이스를 검색하여 제품 재고가 있는 경우 True를, 재고가 없는 경우 False를 반환하는 함수를 테스트한다고 가정해 보겠습니다. 다른 입력 값과 결과 사이에 관계가 없기 때문이 이 시나리오에는 확산 테스트를 사용할 수 없습니다. 이러한 면에서 보면 확산 테스트는 경계 조건 테스트나 쌍별 테스트와 비슷합니다. 즉, 특정 상황에만 적용할 수 있는 기법입니다.

다른 확산 테스트의 예를 살펴보겠습니다. 표준 정규 z 값을 받고 음의 무한대부터 z까지 표준 정규(벨 모양 곡선) 분포 미만의 영역을 반환하는 함수 Gauss(z)를 작성한다고 가정해 보겠습니다. 예를 들어 Gauss(-1.645) = 0.0500, Gauss(1.645) = 0.9500 및 Gauss(0) = 0.5000입니다. 확산 테스트를 사용하는 한 가지 방법은 Gauss의 단조 속성을 기록하고 음의 무한대부터 2.5까지 모든 z 값에 대해 Gauss(z + 0.1)의 결과가 Gauss(z)보다 커야 한다는 것입니다. 확산 테스트를 사용하는 다른 방법은 Gauss의 대칭 속성을 기록하고 0.0 미만의 z 값에 대해 Gauss(-z) = 1.0 - Gauss(z)라는 것입니다.

필자가 소개한 세 가지 예는 가장 일반적인 것이지만 확산 테스트를 적용할 수 있는 유일한 시나리오는 분명 아닙니다. 첫째 시나리오에서는 반복 관계로 정의할 수 있는 수학 함수를 테스트했습니다. 둘째 시나리오에서는 일종의 단조 관계가 있는 함수를 테스트했습니다. 그리고 셋째 시나리오에서는 일종의 대칭 관계가 있는 함수를 테스트했습니다. 확산 테스트는 아니지만 관련된 테스트 유형에는 Sum(x,y)와 같이 입력 값의 순서를 바꾸더라도 반환 값이 바뀌지 않는 함수를 테스트하는 경우가 있습니다.

수학 함수는 반복, 단조 또는 대칭인 경우가 많으므로 확산 테스트를 통해 이익을 볼 수 있는 가장 일반적인 구성 요소 유형이지만 관심을 가져 보아야 할 다른 상황도 있습니다. 반복 관계가 포함되어 있는 수학 함수는 기존 테스트 사례로부터 여러 새 테스트 사례를 생성할 수 있는 경우가 많으므로 확산 테스트에 특히 적합합니다. 그림 1의 데모에서 n = 8, k = 3이고 예상 결과 = 56인 테스트 사례 001으로 n = 9, k = 3이고 예상 결과 = 84인 새 테스트 사례를 생성할 수 있습니다. 이 새 테스트 사례를 사용하여 n = 10, k = 3이고 예상 결과 = 120인 다른 테스트 사례를 생성할 수 있으며 이 테스트 사례가 합격하면 다시 다른 새 테스트 사례를 생성할 수 있습니다.

정리하기 전에 다양한 소프트웨어 테스트 기법과 원리의 명칭과 관련된 바람직하지 않은 현상에 대해 간단하게 이야기해 보겠습니다. 이 칼럼의 테스트 기법을 확산 테스트라고 부른 이유는 확산되거나 분포된 기존 테스트 사례를 사용하여 새 사례를 만들기 때문입니다. 이 기법을 적응 테스트나 자동 생성 테스트와 같은 다른 이름으로 부를 수도 있었을 것입니다. 중요한 것은 명칭이 나타내고 있는 실제 기술이지 명칭 자체가 아닙니다.

소프트웨어 테스트를 포함하여 어떤 연구 분야이든지 자칭 전문가라는 일부 사람들이 상식적인 기법에 명칭을 부여하거나 해당 분야의 초보자들에게 명칭 자체가 중요한 의미를 담고 있는 것처럼 암시하는 이야기를 하는 경우가 있습니다. 이것은 일반적으로 직접 교육 기회를 판매하거나 간접적으로 놀라운 새 명칭에 대한 이야기를 전달하면서 컨설팅 서비스를 판매하기 위한 것입니다. 이러한 용어의 예로 "탐구 테스트"와 "테스트의 컨텍스트 스쿨" 등이 있지만 이 밖에도 많습니다. 그러니까 "확산 테스트"라는 용어는 하나의 소프트웨어 테스트 기법을 설명하는 용어이지만 유용한 테스트 기법이라는 것을 기억하십시오.

Dr. James McCaffrey 는 Volt Information Sciences, Inc.에서 미국 워싱턴 주 레드먼드의 Microsoft 본사에서 일하는 소프트웨어 엔지니어의 기술 교육을 담당하고 있습니다. 그는 Internet Explorer와 MSN Search를 비롯한 여러 Microsoft 제품에 대한 업무 경험을 갖고 있으며 “.NET Test Automation Recipes”(Apress, 2006)를 집필하기도 했습니다. 문의 사항이 있으면 jammc@microsoft.com으로 연락하십시오.

이 문서를 검토하는 데 많은 도움을 주신 기술 전문가인 Bj RollisonAlan Page에게 감사 인사를 전합니다.