테스트란?
- 사소한 코드 오류 하나가 치명적인 사고를 발생시킬수도 있음
- 소프트웨어 테스트는 소프트웨어 내에 존재하지만 드러나지 않고 숨어있는 오류를 발견해 이러한 위험을 사전에 차단하는 것을 목적으로 함
- 테스트는 좁은 의미에서는 소스코드 속에 남아있는 오류를 발견하는 것이지만, 큰 의미에서 보면 개발된 소프트웨어가 고객의 요구를 만족하는지 확인하는 것이 됨. 따라서 테스트의 최종적인 목표는 개발된 소프트웨어에 신뢰성을 높여주는 것이 됨
- 테스트에는 다음과 같은 특징이 있음
- 고객의 요구사항을 충족해야 함
- 테스트 단계 뿐만 아니라 개발 단계에서도 함께함
- 파레토 원리를 적용할 수 있음
테스트에서 발견되는 오류의 80%는 20%의 프로그램 모듈에서 발견된다는 의미
- 모듈 단위를 점점 확대해 나가며 진행함
- 완벽한 테스트는 불가능
- 개발자와 다른 별도의 팀에서 수행함
- pesticide paradox(테스트 케이스에 대한 내성) 해결을 위해 테스트 케이스 업데이트가 필요함
- 테스트를 수행하는데 있어 다음과 같은 문제에 부딛힐 수 있음
- 테스트 케이스가 적고, 완벽하지 않아 효과에 한계가 있음
- 테스트를 위한 실제 사용 환경을 구축하기 어려움
- 개발 환경에서 체크되지 않은 오타와 같은 작은 실수를 발견하기 어려움
- 테스트의 중요성에 대한 인식이 부족함
- 테스트 절차는 테스트 계획 -> 테스트 케이스 설계 -> 테스트 실행 및 측정 -> 테스트 결과 분석 -> 오류 추적 및 수정의 5단계로 구성됨
테스트 계획: 테스트 목표를 정의하고, 테스트 대상 및 범위를 결정하며, 테스트 계획서를 작성하고 검토하는 단계
테스트 케이스 설계: 테스트 계획서를 바탕으로 테스트 설계 기법을 정의하고, 설계 기법에 따른 테스트 케이스와 테스트 코드를 작성하는 단계
테스트 실행 및 측정: 테스트 케이스를 설계한 결과를 바탕으로 테스트 환경을 구축하고, 테스트를 실시하는 단계
테스트 결과 분석: 테스트가 끝날 때 테스트 계획 대비 결과를 비교, 분석함
오류 추적 및 수정: 테스트 결과 발생한 오류를 디버깅 하는 단계
테스트의 분류
- 테스트는 크게 시각에 따른 테스트, 사용 목적에 따른 테스트, 프로그램 실행 여부에 따른 테스트, 소프트웨어 개발 단계에 따른 테스트로 구분됨
시각에 따른 테스트
- 개발 단계마다 개발자의 시각으로 테스트하고 완성된 제품은 사용자의 시각으로 테스트 하게 됨
- 개발자의 시각으로 테스트 하는 경우를 확인 테스트, 사용자의 시각으로 테스트 하는 경우를 검증 테스트라고 함
확인 테스트에서는 설계서의 내용대로 코딩이 이루어져있나를 확인하고, 검증 테스트는 요구분석명세서와 구현 결과물이 일치하는지를 확인하게 됨
- 확인 테스트와 검증 테스트를 같이 사용해야 강력한 테스트가 될 수 있음
사용 목적에 따른 테스트
- 크게 아래의 5개로 분류할 수 있음
- 성능 테스트: 소프트웨어의 성능 요구사항과 소프트웨어 실행 시간을 체크함
- 스트레스 테스트: 평소보다 많은 부하를 발생시키는 테스트
- 보안 테스트: 부당하고 불법적인 침입이 발생했을 때 이를 잘 막아내는지 확인
- 안정성 테스트: 며일 정도 지속적인 부하를 주면서 시스템이 안정적으로 돌아가는지 테스트
- 복원 가능성 테스트: 소프트웨어에 고의로 문제를 발생시키고 소프트웨어 복구가 잘 되는지 확인
프로그램 실행 여부에 따른 테스트
- 프로그램의 실행 여부에 따라서 테스트를 분류할수도 있음
- 프로그램을 실행하지 않고 코드를 검토하며 오류를 찾는 방법을 정적 테스트, 프로그램을 실행하면서 찾는 경우를 동적 테스트라고 함
정적 테스트

- 프로그램 코드를 실행하지 않고 여러 참여자가 모든 명세나 코드를 검토해 소프트웨어의 결함을 찾아내는 방법
결함: 코드의 오류로 인해 프로그램이 완전치 못한 것으로 고장의 원인이 됨
오류: 개발자에 인해 생기는 실수
고장, 실패, 문제, 장애: 시스템이 요구사항대로 작동하지 않는 경우
- 프로그램 코드 분석뿐만 아니라 HTML, XML과 같은 산출물도 검토할 수 있음
- 크게 정형 방법과 비정형 방법으로 분류 가능하고 비정형 방법은 비공식 검토와 공식 검토로 구분할 수 있으며, 공식 검토를 수행하는 절차는 다음과 같음

- 개별 검토에서는 체크리스트를 가지고 본인이 개발한 코드와 산출물 등을 검토하게 됨
- 동료 검토는 동료에게 개발한 소스코드나 결과물을 분석하게 함
- 검토회의에서는 개발자가 소집한 전문가들과 함께 개발자의 작업을 검토하게 됨
- 소프트웨어 검사는 검토회의를 발전시켜 발견된 문제점들을 어떻게 수정해야할지 지침까지 제시해주게 됨
소프트웨어 검사는 소프트웨어 개발 전 과정에 걸쳐 수행하게 되며, 설계를 검사하는 과정과 소스코드를 검사하는 내용은 아래와 같음

소프트웨어 검사의 절차는 다음과 같음

동적 테스트
- 테스트 데이터를 이용해 실제 프로그램을 실행함으로써 오류를 찾는 테스트
- 테스트 정보를 얻는 문서 종류에 따라 명세 기반 테스트와 구현 기반 테스트로 구분 가능
명세 기반 테스트
- 프로그램 내부의 구조나 알고리즘을 보지 않고 요구분석명세서나 설계서에서 테스트 케이스를 추출해 테스트 하는 방법
- 기능을 어떻게 수행하는가보다는 사용자가 원하는 기능을 수행하는가에 대해 테스트 함
- 명세 기반 테스트 방법으로는 신택스 기법, 동등 분할 기법, 경계 값 분석 기법, 원인-결과 그래프 기법, 의사결정 테이블 기법 등이 있음
신택스 기법: 웹사이트의 회원 가입 규칙과 같이 문법을 정해두고 적합/부적합 입력값에 따른 예상 결과가 제대로 나오는지 테스트 하는 기법
동등 분할 기법: 입력 값에 대한 예상 결과 값을 미리 정해놓고, 각 영역에서 임의의 값을 하나 정해 입력값으로 사용해 테스트 하는 기법
경계 값 분석 기법: 이상, 미만과 같은 용어 혼동을 방지하기 위해 경계값과 전후의 값을 테스트하는 기법
원인-결과 그래프 기법
- 원인에 해당하는 입력 조건과 그 원인으로부터 발생하는 출력 결과를 가지고 테스트하는 기법
- 여러 입력 조건을 결합해 하나 이상의 결과를 얻어낼 수 있음
- 원인에 해당하는 입력 조건과 원인으로부터 발생하는 출력 결과를 바탕으로 원인결과 그래프를 만듬
- 원인-결과 그래프를 기초로 의사결정 테이블을 만들고, 테스트 케이스 위한 데이터를 이를 활용해 작성함
- 그래프로부터 테스트 케이스를 만드는 과정은 다음과 같음
- 프로그램을 적합한 크기로 분할
- 원인과 결과를 찾아 원인-결과 그래프를 작성함, 이 때 그래프에서 사용되는 기호는 아래 사진과 같음

- 그래프에 제한 조건을 표시함, 제한 조건 표시시 사용하는 제한 조건 기호는 아래 사진과 같음

- 입력 항목과 결과를 바탕으로 모든 경우의 수를 표현한 의사결정 테이블을 작성하고 예상되는 결과를 표기함
- 의사결정 테이블을 기반으로 테스트 케이스를 작성함
구현 기반 테스트
- 프로그램 내부의 코드를 바탕으로 테스트를 하는 방법
- 명세 기반 테스트와 마찬가지로 입력 데이터를 가지고 실행 상태를 추적하면서 오류를 찾아냄
- 테스트 절차는 다음과 같음
- 테스트 데이터 적합성 기준, 즉 어떤 경로를 테스트 대상으로 선정할지 결정해야 함
- 테스트 데이터 생성
- 테스트 실행, 테스트 방법으로는 문장 검증 기준, 분기 검증 기준, 조건 검증 기준, 분기/조건 검증 기준, 다중 조건 검증 기준, 기본 경로 테스트가 있음
문장 검증 기준
- 소스코드 내의 모든 문장이 최소한 한 번은 실행될 수 있는 테스트 데이터를 갖는 테스트 케이스를 선정함
다음과 같은 과정으로 수행함
- 소스 코드를 제어 프름 그래프 형태로 표현

- 가능한 모든 경로를 구하고, 모든 경로 중 문장 검증 기준을 맞는 경로(a->c->e)를 선택함
- 선택한 경로에 맞는 테스트 데이터를 가지고 실행함
- 다른 검증 기준에 비해 약하고 최소한의 테스트만을 진행하게 됨
분기 검증 기준
- 조건문에 대해 True, False가 되는 경우가 최소 한번은 실행되는 입력데이터를 테스트 케이스로 사용
- 앞선 그림과 같이 하나의 경로만으로는 분기 검증 기준을 만족하지 못하는 경우는 2개 이상의 경로를 묶어서 테스트 해야 함
- 문장 검증 기준보다는 강하지만, 테스트 케이스에 빠지는 부분이 여전히 존재함
조건 검증 기준
- 앞선 2가지 경우에서는 조건문을 기준으로 True, False를 고려함
- 반면 조건 검증 기준에서는 전체 조건식을 무시하고 개별 조건식들에 대해서 True, False가 한번씩은 수행될 수 있도록 테스트 케이스를 설정함
분기/조건 검증 기준
- 개별 조건식 뿐만 아니라 전체 조건식 역시 고려하는 방법
- 분기/조건 검증 기준을 사용하더라도 확인이 불가능한 케이스가 발생할 수 있음
- 어떠한 개별 조건식이 다른 조건식의 결과와 상관없이 결정되는 케이스가 존재할 수 있으며 이를 마스크(mask)라고 부름
다중 조건 검증 기준
- 분기/조건 검증 기준의 mask 현상을 해결하기 위해 사용되는 검증 기준
- and, or로 연결된 개별 조건식에서 하나의 식이 각각 False, True일 때 나머지 식은 True, Flase인 경우를 모두 확인해보는 방법
기본 경로 테스트
- 소스코드의 독립적인 경로가 최소한 한 번은 실행되는 테스트 케이스를 찾아 테스트를 하는 방법
- 절차는 다음과 같음
- 순서도 작성

- 흐름 그래프 작성

- 순환 복잡도를 구함, 이 때 순환 복잡도는 화살표와 노드로 완전히 둘러싸인 구역의 수를 의미하며 앞선 그림에서 순환 복잡도는 3이 됨
- 독립적인 경로를 정의함, 이 때 독립적인 경로의 수는 순환 복잡도와 동일한 3개임
- 테스트 케이스를 작성해 테스트를 실행 함
소프트웨어 개발 단계에 따른 테스트
- 소프트웨어 개발 단계의 순서와 짝을 이루어 테스트를 진행해 나가는 방법

- 그림과 같이 요구분석, 아키텍쳐 설계, 모듈 설계, 구현 단계와 단위 테스트, 통합 테스트, 시스템 테스트, 인수 테스트가 V자 형태로 연결되기 떄문에 V 모델이라고도 부름
단위 테스트
- 프로그램의 기본 단위인 모듈을 테스트하며, 모듈 테스트라고도 부름
- 각 모듈의 개발을 완료하고 개발자가 요구분석명세서대로 정확히 구현되었는지를 테스트하며, 구현 기반 테스트와 같은 구조적 테스트를 주로 시행함
- 상위 모듈과 하위모듈을 가상으로 사용해야하는 경우도 있는데, 상위 모듈의 역할을 하는 가상의 모듈을 테스트 드라이버, 하위 모듈의 역할을 하는 가상의 모듈을 테스트 스텁(test stub)이라고 부름
- 단위 테스트를 통해 잘못 사용한 자료형과 논리 연산자, 알고리즘 오류, 틀린 계산 수식, 무한 루프 등의 오류를 발견할 수 있음
통합 테스트
- 단위 테스트가 끝난 모듈을 통합하는 과정에서 발생할 수 있는 오류를 찾는 테스트
- 모듈간의 상호작용이 올바르게 수항하는지르 체크함
- 모듈 통합을 한꺼번에 할 수도 있지만 오류가 발생했을 때 디버깅이 어려워짐
- 모듈 통합을 점진적으로 하는 경우가 많은데, 상위에 있는 모듈부터 테스트하는 경우는 하향식 기법, 하위에 있는 모듈부터 테스트 하는 경우는 상향식 기법으로 부름
시스템 테스트
- 통합 테스트가 끝나면 시스템 전체가 정상적으로 작동하는지 확인하는 테스트
- 모듈이 모두 통합된 후 사용자의 요구사항을 만족하는지 테스트 하게 됨
- 요구분석명세서에 명시한 기능 요구사항과 비기능 요구사항을 충족하는지 테스트하며, 주로 부하를 주는 상황에서 비기능 테스트를 중심으로 수행함
- 개발자가 진행하는 마지막 테스트가 됨
인수 테스트
- 시스템의 동작 여부를 사용자가 테스트하게 됨
- 사용자가 개발자에게 프로젝트를 발주할 때는 인수테스트를 통해 요구사항을 모두 만족시키는지 확인하게 됨
- 일반인들을 대상으로 제품을 만들어 판매할 때는 회사 내부에서 진행되는 알파 테스트와, 특정 사용자들에게 배포해 테스트를 진행하는 베타 테스트를 수행하게 됨
회귀 테스트
- 확정 테스트 이후 모듈의 수정이 관련된 모듈에 영향을 끼치는지 테스트를 하는 과정
확정 테스트: 소스코드의 결함을 수정한 후 제대로 수정되었는지를 확인하는 테스트
- 버그 수정을 위한 테스트인 수정을 위한 회귀 테스트, 버전 업데이트를 위한 점진적 회귀 테스트로 나뉨
출처:
쉽게 배우는 소프트웨어 공학 2판, 김치수, 한빛아카데미