The ART of Software Testing 을 읽고...(1)

in #kr7 years ago (edited)

안녕하세요. Glenn 입니다.

현업에서 개발자이자 SDET (Software Development Engineer in Test) 으로써 활동하고 있는 사람으로  4년전쯤에 Testing에 대해 공부하며 읽고 기록했던 문서가 남아있더라구요. (제 개인적인 생각이지만 코드 품질을 높이기 위해서는 역시 제대로된 설계와 테스트가 중요한 부분을 차지한다고 경험적으로 깨닫게 되었습니다.)

위의 책을 보면 누구나 알 수 있지만 개인적인 공부를 위해 만들어두고 몰래 꽁꽁 숨겨둔 문서(라 쓰고 독후감이라고..)를 한번 공유 해봅니다.

저보다 실력이 좋으신 분들도 많고, 다른 견해를 지니신 분도 많겠지만 다른 사람들에게 도움이 될 까 해서 용기내봅니다.

스팀은 절 춤추게 만드는군요 ㅎㅎㅎ.
다른 블로그보다 소통도 잘되는 것 같고 너무 좋습니다.

전체 페이지가 스무페이지를 넘기다보니 글이 길어져 천천히 여러번에 걸쳐 포스팅을 해야할 것 같네요.

------------------

 The ART of SOFTWARE TESTING 도서를 정독한 후, 해당 내용들을 정리함과 동시에 현업에 적용해 본다는 생각으로 도서를 요약한다. 이 도서를 읽고 난 후, 현재 진행하고 있는 xxxxxxx 라는 프로젝트의 테스트 과정을 생각해 보면 현재 진행하고 있는 테스트로는 상용화를 시키기에 부족하다고 생각하게 되었으며, 동시에 어떻게 개선해야 할지에 대한 방향이 어느 정도 보이게 되었다. 

많은 개발자 혹은 개발팀들이 프로젝트 산출물을 검증하기 위해 이해 관계자들을 이용하여 테스트를 시도하고, 그 결과를 사용하여 실패하곤 한다. 그 이유는 이해관계에 놓인 테스터들이 테스트의 용어를 잘못 이해하고 있어 테스트시 가지는 자세가 다르기 때문이다. 

일반적으로 프로그래머는 테스트를 “프로그램에 에러가 존재하지 않는다는 것을 확인하는 프로세스다” 혹은 “테스트의 목적은 프로그램이 의도된 기능을 정확히 실행하는지 여부를 확인하는 것이다”와 같이 생각한다. 하지만 테스트는 프로그램 품질과 신뢰성 제고를 의미하는 것으로, 에러를 찾기 위해 프로그램을 실행하는 프로세스이다. 

사실 일반적으로 본인뿐만 아니라 주변의 프로그래머들은 소프트웨어 테스트를 진행할 때, 자신의 실력을 과신해서인지 에러가 나지 않는 방향으로 positive한 케이스만을 테스트하지 에러를 잡기 위한 negative한 케이스는 잘 테스트하지 않았다. 이런 것으로 보면 테스트는 인간의 기질에 반대되는 행위이다. 

그렇다면 테스트의 성공과 실패는 무엇으로 구분할 수 있는가? 물론 본인 입장에서는 프로그램이 에러를 내보내지 않으면 성공이라고 생각하겠지만 실제로 테스트의 성공 여부는 프로그램에 내재된 에러를 얼마나 많이 잡아내느냐에 따라 달라진다. 

프로그램은 인간이 설계하고 개발하여 완벽할 수 없으므로, 프로그램 테스트를 진행하여 어떠한 에러도 발견하지 못한다면 테스트 전략 및 테스트 케이스와 같은 것들이 잘못 되었다고 생각해야 하며 이는 테스트 실패라고도 볼 수 있다. 하지만 테스트를 진행하여 많은 에러를 찾아내고 이를 수정하여 에러 빈도를 줄여 나간다면 프로그램이 고객에게 주는 가치가 상승하게 되며 이는 곧 회사의 이익과도 직결되므로 성공이라고 볼 수 있다. 

그렇다면 이런 성공적인 테스트를 하기 위해서 어떤 전략을 세워야 하는가?

그냥 무작정 100% 완벽한 프로그램을 만들기 위해 테스트 시도를 한다면 이는 비현실적이며 경제학적으로도 어긋난다. 테스팅의 경제학과 관련한 이런 문제를 해결하기 위해서는 전략을 세워야 한다. 가장 일반적인 전략이 아래에서 설명할 블랙 박스 테스팅과 화이트 박스 테스팅이다. 블랙박스 테스팅은 데이터 주도 테스팅 또는 입출력 주도 테스팅이라고 한다. 이 방법에서는 테스트 대상인 프로그램은 내부를 볼 수 없는 하나의 블랙 박스로 본다. 즉, 내부가 어떻게 동작하는 상관없고 정의된 프로그램 명세대로 동작하지 않는지를 확인하는 것이다. 이렇다보니 프로그램에 전문적인 지식이 없더라도 기계적으로 테스트 데이터를 만들어 낼 수 있어 여러 사람이 함께 진행하기에 유용하다.

하지만 블랙 박스 테스팅을 통해 프로그램의 모든 에러를 발견하기 위해서는 테스트 케이스로 가능한 모든 입력을 사용하는 철저한 입력 테스팅을 해야 한다. 하지만 완벽한 테스트를 위해 모든 입력에 따른 테스트 케이스를 만들어 테스트를 진행하면 좋겠지만 단순해 보이는 프로그램도 무수히 많은 입력과 출력의 조합을 갖기 때문에 대부분의 경우는 불가능하다. 그러므로 전략적으로 테스트를 수행해야 한다. 

블랙박스 테스트와 다른 방법으로 화이트 박스 테스트가 존재한다. 이는 프로그램의 내부 구조를 조사하는 것으로 사양을 무시하면서까지 프로그램의 로직을 조사해 테스트한다. 즉 프로그램의 모든 제어 흐름 경로를 여러 가지 방법으로 실행하여 프로그램의 경로를 완벽하게 테스트하는 것이다. 

하지만 프로그램 내 로직 경로의 수가 천문학적이며 프로그램 자체의 사양을 테스트 하기에는 힘든 문제가 있으므로 블랙 박스 및 화이트 박스 테스트, 이 두 가지 방식을 적절히 섞어 테스트를 해야 한다. 

위에서 예로 든 2가지 테스트 방식을 효율적으로 잘 사용하기 위해서 몇 가지 중요한 테스팅 기준이 필요한데 아래에 기술하겠다. 

소프트웨어 테스팅 원칙 

원칙 1. 테스트 케이스의 필요한 부분은 예상 출력이나 결과에 대한 정의다.
원칙 2. 프로그래머는 자신의 프로그램 테스트를 피해야 한다.
원칙 3. 프로그래밍 조직은 자신들의 프로그램을 테스트하지 말아야 한다.
원칙 4. 테스트 결과를 철저하게 조사해야 한다.
원칙 5. 유효하고 예상 가능한 입력 조건에 대한 테스트 케이스 작성은 물론, 무효하고 예상치 못한 입력 조건에 대해서도 테스트 케이스를 작성해야 한다.
원칙 6. 프로그램이 해야 할 것을 하지 않는지에 대한 조사도 중요하지만, 프로그램이 하지 말아야 할 것까지 하는지도 찾아내야 한다.
원칙 7. 한 번 사용하고 버리는 프로그램이 아니라면, 사용하고 버리는 테스트 케이스를 만들면 안 된다.
원칙 8. 에러를 발견하지 못할 것이라는 암묵적인 합의 하에 테스트 수행 계획을 작성하면 안 된다.
원칙 9. 프로그램의 한 섹션에 많은 에러가 있을 가능성은 그 섹션에서 발견될 에러의 수에 비례한다.
원칙 10. 테스팅은 극도로 창의적으로 지적인 도전이다. 

일반적으로 프로그래머들이 생각하는 테스트와 지금까지 말한 테스트의 원칙은 프로그램에 대한 테스트이다 (소프트웨어는 개발 명세, 개발 문서, 프로그램과 같은 산출물을 의미하므로 소프트웨어는 프로그램과 같은 용어가 아니다.). 

그런데 70년대 초부터 코드를 읽는 것이 의미론적으로 테스팅과 디버깅의 한 부분으로 인식되면서 컴퓨터에 기반하지 않은 인간에 의한 테스팅 프로세스가 발전하기 시작했다. 이는 에러를 찾는데 꽤 효과적이기 때문에 거의 모든 프로젝트에서 한가지 이상의 기법이 사용된다. (인간 기반 테스팅은 프로그램 코딩이 완료되고 컴퓨터 기반 테스팅이 시작되기 전에 적용해야 한다. 인간 기반 테스팅은 비정형적이라 회의적이라고 생각할 수도 있으나, 사실은 반대다.) 

이 중요한 인간 기반 테스팅 중 가장 대표적인 두 가지 테스팅 방법이 바로 인스펙션과 워크스루이다. 일단 인스펙션과 워크스루는 프로그램을 읽고 시각적으로 검사하여 에러를 찾는 것이다. 즉 에러의 해결책을 찾거나 디버깅을 하는 것이 아니라 에러 자체를 찾는 것이다. 

이 인간 기반 테스팅의 두 가지 방법은 프로그램 개발자가 아닌 다른 사람이 프로세스에 참여하고 코드 및 문서를 보고 에러를 찾는 것으로 에러 발견 시 에러의 위치가 바로 드러나므로 디버깅 시간을 줄일 수 있다는 이점이 있다. 다만 이 인간 기반 테스팅 프로세스는 단지 쉬운 에러만 찾을 수 있으며, 어렵고 애매하고 까다로운 에러는 컴퓨터 기반 테스팅으로만 발견할 수 있다는 통계 때문에 비난이 따를 수 있다. 그러나 특정 종류의 에러를 발견하는데 이 인간 기반 테스트가 효과적이기 때문에 많은 테스터들이 이 방법을 사용하고 있다. 

즉 컴퓨터 기반 테스팅 및 인간 기반 테스팅을 어느 하나만 사용해서는 이득을 얻을 수 없는 상호 보완적 관계인 것이다. 

코드 인스펙션 (Code Inspection) 

코드 인스펙션은 일련의 절차에 따라 참여자가 함께 코드 읽기를 하여 에러를 탐색하는 기법이다. 인스펙션 팀은 일반적으로 중재자, 프로그래머, 테스트 전문가, 설계자이다. 중재자는 인스펙션 회의 자료 배포 및 일정 관리, 회의 주재, 발견한 에러 기록, 나중에 수정된 에러 확인 등의 역할을 맡아서 하는 인스펙션 방식의 품질 관리 엔지니어이다. 

일단 중재자는 회의 며칠 전에 프로그램 리스트와 설계 명세를 배포한다. 그리고 참석자들은 회의 전에 자료를 검토해야 하며 회의 중에 이 팀 멤버들이 하는 활동은 딱 두 가지이다. 

1. 프로그래머가 프로그램 로직을 문장 단위로 읽는 것. 

2. 일반적인 프로그래밍 에러 체크 리스트에 따라 프로그램을 분석. 

그리고 중재자는 회의가 생산적으로 진행되고 참석자가 에러 수정이 아닌 찾기에 집중하도록 해야 한다. (현업에서 코드 인스펙션을 수행해본 결과, 개발자는 자신의 코드와 자신을 동일시하여 지적질을 참지 못하는 경우가 굉장히 많으며 참석자들은 자신의 취향과 맞지 않는 코드는 신랄하게 비판하더라...)프로그래머는 인스펙션 회의 후에 에러를 수정한다. 사실 인스펙션을 어느 정도 적용시켜 프로젝트 자체의 코드 리뷰 프로세스를 구성하여 사용해 봤기도 하였고, 프로그래머로써 직접 참여도 하여 코드 품질을 높이는 활동을 했음에도 불구하고 가장 안 되는 것이 에러가 발견되었을 때의 반응이었다.

 일단 대다수의 프로그래머들은 에러를 찾게 되면 그 문장을 작성한 이유에 대해 변명하기도 하고 그 자리에서 수정을 하려고 코드를 건드리기도 한다. 우리나라 사람들은 코드와 자신을 일치시켜 생각하는 경우가 많아 단순한 문법 에러가 아닌 구조적인 문제를 들고 나오는 경우, 기분을 많이 상해하는 것을 볼 수 있었다. 

이런 것을 중재자가 잘 처리해야 나머지 시간이 유익하게 사용될 수 있었다. 인스펙션은 문장 하나하나를 읽어 가며 검증을 하는 고도의 집중력을 요하는 테스트로써 외부의 방해를 피할 수 있어야 하므로 외진 회의실에서 진행해야 하며, 집중력이 떨어지지 않도록 90~120분 정도만 진행해야 한다. 

워크스루 (Walk-through) 

워크스루는 참여자들이 함께 코드 읽기를 위한 절차와 에러 검출 기법이다. 인스펙션과 많은 공통점이 있지만 절차와 에러 검출 기법이 다르다. 워크스루는 세 명에서 다섯 명 정도로 구성되는데 일단 필수로 있어야 하는 참가자는 참가자는 인스펙션 과정에서도 필수적인 중재자, 다른 사람은 발견한 모든 에러를 기록하는 서기가 있으며, 나머지 사람들은 프로그래머나 전문 지식을 가진 테스터로 에러 검출 역할을 한다. 

처음 절차는 인스펙션과 동일하게 중재자가 참가자들이 프로그램을 연구할 수 있도록 며칠 전에 자료를 송부한다. 하지만 회의는 인스펙션과 약간 다르게 진행된다. 참가자는 컴퓨터 역할을 하는 것으로 테스터로 지정된 참가자는 회의에 참가할 때 프로그램이나 모듈의 입력 값을 대표하는 문서로 된 테스트 케이스를 준비하고 회의 중에 그 테스트 케이스는 생각으로 실행된다. 테스트 케이스가 중요한 부분을 차지하는 것은 아니고 테스트 케이스를 사용하여 프로그램을 수동으로 구동하면서 프로그래머에게 논리와 가정에 대해 질문한다. 

대부분의 워크스루에서 테스트 케이스로 발견되는 에러보다 프로그래머에게 질문하는 과정에서 더 많은 에러가 발견되다. 인스펙션과 마찬가지로 참가자의 태도가 워크스루의 성패에 결정적이다. 테스터들은 프로그래머와 프로그램을 동일시하면 안되고 프로그램에 대한 지적을 해야지 프로그래머를 지적 해서는 안 된다. 

그 외에도 한 사람이 하는 인간 기반 에러 탐색 프로세스인 데스크 체킹과 코드 읽기를 하는 동료 평가가 있다. 

그렇다면 앞에서 나온 몇 가지 테스트 기법 및 앞으로 계속 쓰일 프로그램 테스트에서 가장 중요한 고려 사항인 효과적인 테스트 케이스 설계와 작성에 대해 알아본다. 앞에서 말한 것처럼 완전한 테스팅이 불가능하기 때문에 테스팅은 에러가 없음을 완벽히 보장하지 못한다. 그러므로 테스트 케이스를 전략적으로 만듦으로 주어진 비용 및 시간 내에서 가장 최선의 테스트를 진행 할 수 있도록 해야 한다. 

이런 효율적인 테스트 케이스를 위해 가장 우선적으로 생각해야 하는 것은 “가용한 테스트 케이스의 어떤 부분 집합이 에러를 가장 많이 찾아낼 수 있는가?” 이다. 이 집합을 찾아내기 위해서 앞서 설명한 블랙 박스 테스트와 화이트 박스 테스트 내의 방법론들을 상호 보완적으로 사용해야 하는데 상세한 방법론들은 다음과 같다.     

 위 방법론들을 효율적으로 사용하기 위해서는 블랙 박스 방법을 사용해 테스트 케이스를 개발하고 화이트 박스 방법으로 필요한 테스트 케이스를 보충하는 것이다. 

--------------------

2편에서 계속할게요... (이건 내일 ㅠㅠ)

Sort:  

테스팅 관련 글을 보게 되어 반갑네요...
SDET 조직을 갖고 있는 회사가 많지는 않은데, 제가 아는 회사가 아닌가 모르겠네요...

아..아하핫...... 부끄럽습니다.

감사합니다. ㅎㅎㅎ

저도 TDD 시도를 많이 하고 있습니다만 실력이 부족해서인지 이게 참 어렵더라구요.
제 개인적으로 TDD의 가치는 test code 의 요구사항화, 그리고 regression에 두고 있습니다만 개발기간에 쫒기다보면 유지보수가 안되어 항상 실패합니다. 테스트 코드를 잘 만드는 것이 결국 개발기간을 줄인다는 것을 알고 있으면서도 자기 자신에게 기간 탓을 하며 변명하네요. ㅠㅠ

마지막 글귀가 참 좋습니다.
"코딩은 작문에 가깝다. 쉽고 누구나 이해할 수 있는 작문은 처음부터 되는 것은 아니다.
반복적인 연습을 통해 이룩될 수 있으며, 이는 하면 할 수록 향상되며 결코 실패하지 않는다."

앞으로 좋은 글 많이 부탁드립니다. ^^

대학교 4학년 1학기 소프트웨어 공학 때 한번 쯤 배웠거나 스-윽하고 지나갔을 법한 내용들이네요. 졸업하고 게임개발하느라... 좀 잊었지만...

프로그래밍 내용은 언제나 좋아요. 그래서 아낌없이 보팅을합니다..

감사합니다. 그런데 이시간까지 안주무시고 열일 하시나봅니다.
힘내십시오!

아뇨 오늘은 아까 낮에 방송을 한 8시간 가까이 하면서 개발했구요. 밥먹고 좀 쉬고 있었습니다. 이제 슬슬 자야겠어요. 글렌님도 늦게 까지 안주무시는거 같네요. 안피곤하신지요

유부남에게 이 시간은 황금과도 같습니다. ㅋㅋㅋㅋㅋ
내일 아침 7시에 일어나야 할지라도 이 시간은 절대 양보 못합니다. 캬캬캬캬....

싱글인지라.. - _-;; 미쳐 몰랐습니다.

아...아닙니다. 하지만 이제 곧 데드라인이 다가오고 있군요.
20분동안 놀다가 자야겠습니다. ㅠㅠ @krdoko 님도 즐거운 밤 되세요!