테스트

BiteSnail·2023년 12월 7일
0

테스트 기초

소프트웨어 개발은 인간 중심의 지적활동이기 때문에 거의 모든 개발비는 인건비라고 생각할 수 있습니다. 또한 지적 활동이므로 오류가 발생하기 쉬운 활동입니다.

따라서 결함을 낮추기 위해 노력해야 하며 코딩 단계에서 인스펙션이나 정적 분석을 통해 결함을 방지하고 테스트나 디버깅을 통해 결함을 제거해야 합니다.

테스트

테스트는 개발 단계에서 가장 많은 시간과 예산이 소모되는 작업입니다. 가능한 많은 테스트 케이스를 통해 프로그램이 문제 없이 작동한다는 것을 검증할 수 있어야 하기 때문입니다.

가장 완벽한 테스트 케이스는 입력 및 출력 값 범위에서 가능한 모든 값을 주고 테스트 해보는 것입니다. 하지만 이것은 불가능하기 때문에 적절한 테스트 케이스를 선택하는 것이 중요합니다.

검증과 확인

검증(verification)은 개발된 소프트웨어가 설계 문서와 일치하는지, 오류 없이 작동하는지, 모든 함수가 예상대로 작동하는지 등을 확인하는 과정입니다.

확인(validation)은 최종적으로 요구사항과 기대치를 만족시키는지를 평가하는 과정입니다.

기본적으로 개발 단계에서 거론되는 테스트는 검증 과정이 압도적으로 많습니다.

오류의 종류

버그(bugs)

버그는 문제나 결함을 나타내는 데 일반적으로 사용되는 용어입니다.

오류(error)

오류는 개발자가 설계나 코딩에 실수한 것을 의미합니다. 프로그램의 출력이 예상과 다르다면 이것 또한 오류라고 할 수 있습니다.

결함(defect)

결함이란 시스템이 고장을 일으키게 하는 오류의 결과입니다. 오류가 있는 경우 결함이 발생하는데, 일부 오류는 결함이 즉각적으로 나타나지 않을 수도 있습니다.

고장(failure)

고장이란 시스템이 정상적인 작업을 수행할 수 없는 상황을 의미합니다. 보통 고장은 결함 때문에 발생하는데, 결함들이 우연히 맞물리며 고장 현상이 발생하지 않을 수도 있습니다. 이는 정말 위험한 상태로 주의해야 합니다.

테스트 작업 과정

테스트는 1. 무엇을 점검할 것인지 결정하고 2. 테스트 방법을 선택한 후 3. 테스트 케이스와 4. 올바른 결과(test oracle)를 작성합니다. 그리고 5. 테스트 케이스를 실행하여 결과를 확인합니다.

회귀 버그는 이전에 제대로 작동하던 소프트웨어 기능에 문제가 생기는 것을 말합니다. 이는 프로그램 변경 중에 뜻하지 않게 발생하는 것으로 이를 찾는 모든 테스트 방식을 회귀 테스트라고 할 수 있습니다.

테스트 케이스

테스트 케이스는 결함을 발견할 목적으로 준비한 입력 데이터와 예상결과의 집합입니다.

실제 서비스에서는 테스트 케이스를 벗어나는 행동이 발생할 확률이 분명 존재하므로 테스트 케이스라도 100% 통과를 목표로 해야 합니다.

  • 속성 - 이름, 테스트 대상, 조건, 입력, 오라클, 로그 등이 있습니다.
  • 테스트 슈트 - 테스트 케이스의 모임입니다.
  • 테스트 절차 - 테스트 케이스를 어떤 순서로 수행할 것인지 적은 것입니다.
  • 테스트 스텝 - 테스트 케이스를 실행하기 위한 최소의 단위입니다. (로그인도 하나의 스텝이 될 수 있습니다.)

블랙박스 테스트

블랙박스 테스트는 내부 경로에 대한 정보 없이 테스트 대상의 기능이나 성능만을 테스트하는 것입니다. 이 때문에 테스터와 개발자가 서로 방해하지 않고 각각을 준비할 수 있다는 장점이 있습니다. 크고 복잡한 프로그램의 테스트에 적합합니다.

하지만 테스트할 시나리오의 세세한 조건을 설정하기가 어렵기 때문에 일부 케이스가 누락될 수 있습니다.

동등 분할 기법

동등 분할 기법은 시스템의 동작이 같은 것으로 예상되는 입력을 묶어서 테스트 하는 것 입니다. 예를들어 비밀번호의 길이가 10~20 자로 제한해야 한다는 입력에 대한 테스트 케이스는 다음과 같이 정의할 수 있습니다.

InvalidValidInvalid
≤1010~20≥21

위처럼 3개의 그룹으로 나눌 수 있으며 각 그룹에서 적당한 값을 골라 테스트하여 모두 정상적으로 작동하는지 확인합니다.

경곗값 분석

동등 분할 기법에서 조금 더 업그레이드 된 방법으로 특정 그룹이 구분되는 경계값을 기준으로 문제가 발생할 확률이 높기 때문에 이를 이용하여 테스트합니다.

문자열의 길이를 10~20자로 제한하는 경우 경계값은 다음과 같습니다.

1020
9, 10, 1119, 20, 21

이 때 경계값들에 대한 테스트 케이스를 작성하여 모두 정상적으로 작동하는지 확인합니다.

원인과 결과 그래프

입력 조건의 조합을 체계적으로 선택하는 기법으로 노드(원인이나 결과)와 기호(and: ^, or: ∨, not: ~)를 통해 표시합니다.

결정 테이블

아래 그림과 같이 그래프의 결과에 대해 테이블로 작성한 것입니다. E1의 경우에는 C3,과 C4와 연결되어 있지 않기 때문에 dont care 인 x로 표시하고 C1 or C2에 not이 붙었으므로 드모르간 법칙에 의해 ~C1 & ~C2로 바뀝니다. 따라서 0 0 x x 가 E1에 대한 C 값들입니다.

화이트박스 테스트

화이트박스 테스트는 모듈의 논리적인 구조를 체계적으로 점검하는 것입니다. 내부 구조를 기반으로 테스트하기 때문에 블랙박스 테스트 방식보다 더 정확하고 세밀한 검증이 가능합니다.

테스트 과정

소스 코드를 통해 논리 흐름도를 작성한 후 검증 기준을 골라 그 경로를 만족할 수 있는 테스트 케이스를 준비합니다.

검증 기준

커버리지는 테스트된 아이템의 비율을 의미하며 퍼센티지(%)로 표시할 수 있습니다. 이는 아래와 같은 수식으로 계산할 수 있습니다.

테스트 한 경로기본 경로의 총 수\text{테스트 한 경로}\over\text{기본 경로의 총 수}

문장 커버리지

문장(Statement) 커버리지는 소스 코드의 각 라인이 적어도 한 번 실행되는지를 검증합니다. 따라서 테스트 케이스가 모든 문장을 수행할 수 있다면 문장 커버리지를 만족한다고 할 수 있습니다.

결정 커버리지

결정(Decision) 커버리지 혹은 브랜치(Branch) 커버리지는 소스 코드 내의 모든 결정 단계에 대해 True와 False인 경우가 한 번 이상 수행되는지를 검증합니다.

조건 커버리지

조건(Condition) 커버리지는 결정 단계 내에 존재하는 각 개별식에 대해서도 True와 False가 되는 경우가 한 번 이상 수행되는지를 검증합니다.

경로 커버리지

경로(Path) 커버리지는 가능한 모든 케이스들을 검사하는 것입니다.

사이클로매틱 복잡도

시스템이 커지고 복잡해질 수록 경로 커버리지를 만족하는 것은 사실상 불가능에 가깝습니다. 따라서 사이클로매틱(cyclomatic) 복잡도를 구하는 것으로 철저한 테스트 케이스 수를 결정하는 데 도움을 받을 수 있습니다.

사이클로매틱 복잡도는 다음과 같이 구할 수 있습니다.

아래 수식에서 E는 간선의 개수, N은 노드의 개수를 의미하고 Sin은 내부 영역의 수를 의미합니다.

EN+2orSin+1E-N+2\\ or\\ S_{in}+1


논리 흐름도 예시 | 출처 : wikipedia

위의 논리 흐름도에서 사이클로매틱 복잡도는 3으로 구할 수 있습니다.

사이클로매틱 복잡도는 철저한 테스트를 위해 필요한 경로의 개수라고 생각할 수 있습니다. 따라서 사이클로매틱 복잡도는 결정 커버리지와 같거나 클 수 있고 전체 경로의 개수와는 같거나 그보다 작을 수 있습니다.

branch coveragecyclomatic complexitynumber of paths\text{branch coverage}\leq\text{cyclomatic complexity}\leq\text{number of paths}

예를 들어 if문이 연속적으로 존재하는 경우 True/True와 False/False를 만족하는 경로로 결정 커버리지를 만족할 수는 있으나 True/False나 False/True 를 만족하는 경로에 오류(error)가 존재할 수 있습니다. 따라서 총 3개의 경로를 검사함으로써 철저한 테스트를 거쳤다는 것을 보장할 수 있게 됩니다.

(하지만 이렇게 해도 오류는 있을 수 있습니다.)

사이클로매틱 복잡도는 1~10인 경우 구조적으로 안정됨을 의미합니다. 복잡도가 40이상이 되면 테스트가 불가능하고 매우 높은 위험이 존재한다고 할 수 있습니다.

상태기반 테스트

상태기반 테스트는 같은 입력에 대해 같은 동작을 보이며 동일한 결과를 생성하는 시스템을 대상으로 하는 테스트입니다. 각 상태에서 일어날 수 있는 트랜지션에 대해 테스트 케이스를 작성하여 테스트합니다.

상태 모델 구성요소

  • 상태 - 시스템의 과거 입력에 대한 영향을 표시
  • 트랜지션 - 이벤트에 대한 반응으로 하나의 상태에서 다른 상태로 변하는 행위
  • 이벤트 - 시스템에 대한 입력
  • 액션 - 이벤트에 대한 출력

통합 테스트

통합 테스트는 모듈들의 결합을 테스트하는 과정입니다. 모듈의 결합 관계에 따라 방법이 달라집니다.

용어

  • 테스트 하니스(test harness) - 시스템을 테스트하기 위하여 작성된 별도의 프로그램
  • 드라이버(driver) - 시험 대상 모듈을 호출하는 간이 소프트웨어
  • 스텁(stub) - 시험 대상 모듈이 호출하는 또 다른 모듈

통합 방법

빅뱅(big-bang) 통합

한번에 모든 모듈을 모아 통합하는 것으로 통합을 위하여 따로 스텁을 구성할 필요가 없다는 장점이 있습니다. 하지만 모든 요소를 동시에 통합하기 때문에 중대한 오류가 발생할 가능성이 있고 오류의 위치와 원인을 찾기 힘들다는 단점이 있습니다.

하향식(top-down) 통합

시스템 구조상 최상위에 있는 모듈부터 통합하는 것으로 스텁을 이용하여 시스템의 개요를 일찍 구현 가능합니다.

상향식(bottom-up) 통합

하향식과 반대로 최하위 모듈부터 통합하는 것으로 스텁 대신 드라이버가 필요합니다. 하위층 모듈은 지속적으로 테스트되기 때문에 오류 발견이 쉽다는 장점이 있지만 전체 시스템을 시험해볼 기회가 상대적으로 적다는 단점이 있습니다.

시스템 및 인수 테스트

컴포넌트 통합 후 수행하는 테스트 기법으로 기능, 성능(작업 부하, 처리량, 반응시간 등) , 보안, 사용성 등을 테스트합니다.

또한 개발 시스템 환경에서의 테스트(alpha test)와 실제 목표 시스템 환경(beta test)에서 테스트하여 SW 수행을 테스트합니다.

profile
느리지만 조금씩

0개의 댓글

관련 채용 정보