8/06/2023

Software Testing

Software Testing

소프트웨어 테스트는 소프트웨어를 배포하기 전 해당 소프트웨어가 정상적으로 작동하는지 검증하는 단계로 테스트는 크게 단위 테스트, 통합 테스트, 인수 테스트로 나뉜다. 테스트는 코드를 통해서 수행 가능하기 때문에 자동화 처리가 가능하다. 이후 QA 라는 과정을 통해 테스터가 직접 소프트웨어를 테스트 한다. QA는 외주 혹은 개별 팀에서 진행하는 사항을 말한다.

단위 테스트는 각 함수 및 클래스 단위로 진행할 수 있기 때문에 가장 많은 수를 차지한다. 개별적인 테스트들이 통과할 수 있다면 여러 테스트를 결합하여 그 결과들을 검증할 수 있다. 통합 테스트는 모듈들을 조합하여 테스트를 구성하기 때문에 통합 테스트의 수가 상대적으로 더 적다. 인수 테스트는 통합 테스트와 비슷하지만 실제 환경을 가정하고 테스트하는 것을 의미한다. 단위 테스트 및 통합 테스트는 빌드를 올바르게 수행할 수 있는가에 대해서 집중한다면 인수 테스트는 빌드된 소프트웨어가 정상적으로 작동하는가에 초점이 맞춰져 있다. 각 테스트에 대해서 구체적으로 알아본다.

Unit Test

단위 테스트는 소프트웨어를 단위로 분해하여 테스트하는 방식이다. 나눌 수 있는 단위로 함수 및 클래스를 주로 이용하는데 모든 코드가 테스트 하기 쉽게 만들어지는건 아니다. 다시 말해, 단위가 나눠져있는 상태로 개발되는 것이 아니기 때문에 단위로 나누는 과정을 통해 개발 품질을 높일 수 있다. 이를 모듈화라고 하며 테스트 가능하게(testable)라는 의미는 잘 모듈화된 코드라고 볼 수 있다. 단위 테스트는 모듈 하나 하나를 독립적으로 테스트하여 다른 모듈에 영향을 주지 않으면서 안전하게 테스트한다.

Integration Test

통합 테스트는 단위 테스트들을 모아서 테스트하는 방식이다. 상향식 통합 테스트는 모듈들을 모아 테스트한다. 모듈이 있는 것을 가정하고 테스트하는 방법을 하향식 통합 테스트라고 한다.

Acceptance Test

인수 테스트는 통합 테스트에서 더 나아가 실제 환경처럼 맞추어 테스트하는 것을 의미한다. 주로 알파 테스트와 베타 테스트로 알려져 있는 테스트들이 인수 테스트에 속한다. 알파 테스트는 폐쇄적인 환경에서 개발자가 통제를 하여 테스트를 진행하고 베타 테스트는 개방적인 환경에서 비교적 자유롭게 테스트를 진행한다.


Code Coverage

테스트가 코드를 얼마나 커버하는지에 대한 정도로 커버리지는 함수(function), 구문(statement), 조건(condition), 분기(branch)으로 분류된다. 
  • 함수 커버리지: 총 함수 중에 몇 개의 함수가 실행되는 정도를 의미하며 함수가 실행되지 않는다면 다른 커버리지 또한 측정을 할 수 없으므로 테스트들을 포괄하는 개념으로 볼 수 있다. 즉, 함수 커버리지 = 실행된 함수 개수 / 전체 함수 개수 * 100
  • 구문 커버리지: 코드의 하나의 구문이 실행되는 정도를 의미하며 만약 그 하나의 구문이 실행되지 않으면 테스트가 되지 않았다고 볼 수 있다. 즉, 구문 커버리지 = 실행된 구문 개수 / 전체 구문 개수 * 100
  • 조건 커버리지: if 내의 조건들이 true와 false를 가지는 정도를 의미한다. 즉, 조건 커버리지 = 각 조건마다 true 혹은 false 한번의 개수 / (전체 조건 개수^2) * 100
  • 분기 커버리지: 조건으로 인하여 나뉘게 되는 실행 경로를 의미하며 조건이 많아질수록 분기 커버리지의 전체 양이 늘어난다. 즉, 분기 커버리지 = 실행된 분기 개수 / 전체 분기 개수 * 100


History

  • 디버깅 지향 시대: 테스팅을 하는 주된 목적은 버그를 제거하는데에 있었기에 디버깅과 테스팅의 구분이 없었다.
  • 증명 지향 시대: 테스팅의 목적은 소프트웨어의 요구사항을 포함하기 시작하였지만 이전 시대의 디버깅 목적의 성향이 남아 있는 시대이다.
  • 파괴 지향 시대: 테스팅의 목적은 오류를 찾아내는데에 있다. 테스팅을 통해 오류가 발생하였다면 오류를 찾고 수정하는 디버깅이라는 작업으로 나눠지게 되었다.
  • 평갸 지향 시대: 테스팅은 소프트웨어의 개발 생명 주기에 포함되었다. 검토 활동의 가치가 인식되기 시작하여서 테스트의 중요성이 부각된 시대라고 볼 수 있다.
  • 예방 지향 시대: 소프트웨어 개발 전반적인 부분(설계, 디자인, 구현 등)에서 생기는 문제들을 미리 찾아내기 위함으로 테스팅이 진행된다.


TDD

https://www.spiceworks.com/tech/devops/articles/what-is-tdd/

기존 Waterfall 방식으로는 설계 → 개발 → 테스트 코드 작성으로 진행하였지만 TDD에서는 테스트 코드 작성 → 개발 → 리팩토링 방식으로 진행한다. 그래서 테스트 주도 개발이라고 불리우며 이는 테스트 코드가 설계의 역할을 한다고 볼 수 있다. TDD 방식으로 진행하여 처음 테스트 코드를 작성을 하면 해당 테스트는 통과하지 못한다. 이는 테스트하는 함수가 정상적으로 구현되어 있지 않기 때문이다. 이 때, 개발자는 우선 기능이 돌아가게 프로그래밍하여 해당 테스트를 통과하게 만들고 그 다음으로 리팩토링하여 기능이 잘 수행될 수 있게 로직을 개선한다. 이처럼 TDD는 테스트 코드를 먼저 작성함으로써 설계한 후 하드 코딩하여 재빠르게 기능을 구현하고 리팩토링하여 성능 및 안정성을 높인다. 애자일한 소프트웨어 개발 방법론이 부상함에 따라 TDD가 나타나게 되었다.


Why Testing

  • 소프트웨어의 품질 검증 및 보장: 개발 후 잔존해있는 결함 및 버그들을 찾아서 해결할 수 있고 기존 명세대로 프로그램이 개발이 되어 있는지 테스트할 수 있으며 인수 테스트를 통해 사용자의 요구사항을 충족했는지에 관한 부분도 확인할 수 있다. 이를 통해 소프트웨어가 해결해야할 문제를 정확하게 캐치하고 풀어나가는 과정이라 할 수 있다.
  • 유지 보수 시 오류 방지: 기능 추가, 버그 제거, 리팩토링에 있어서 개발자는 어떠한 이유로든 실수할 수 있다. 이 때 기존에 있던 자동화 테스트 코드가 통과되지 않는다면 실수가 어디서 발생했는지 잡아내어 수정할 수 있다. 테스트 코드를 추가하는 습관을 들여 유지 보수하기 쉬운 코드를 만들어야 한다.


Manual Testing vs. Automated Testing

수동 테스트는 개발자 및 사용자가 직접 테스트하는 것을 의미한다. 테스트를 계획하고 수행하고 결과를 도출하는 과정이 있으며 이 과정들을 거쳐야 온전한 결과를 받아볼 수 있기 때문에 수동 테스트는 개발 중 이거나 배포 직전 Q&A에서 진행한다. 주로, 사용성을 검증할 수 있는 UI 및 UX 테스트에서 수행한다. 수동 테스트는 누구나 직관적으로 쉽게 테스트를 실행할 수 있다는 장점이 있지만, 사람이 직접 실행하다 보니 테스트 실행 속도도 느리고 테스트 시나리오에 따라 시간도 오래 걸려서 자주 실행하기가 힘들고 부정확할 확률이 있다는 단점이 있다. 특히, 인력과 시간이 부족할 수밖에 없는 스타트업이나 소규모 기업에서 테스트를 주먹구구식으로 실행할 때가 많기 때문에 시스템 버그가 생길 확률이 높다.

시스템 테스트를 최대한 자동화해서 사람에 의한 오류를 줄이고 항상 정확하며 테스트가 반복적으로 자주 실행될 수 있게 그리고 빠지는 부분이 없이 테스트가 실행될 수 있도록 하는 것이 개발팀의 생산성을 높이고 시스템을 안정적으로 운영할 수 있는 방법이다. 인수 테스트는 프론트엔드부터 백엔드까지 모든 시스템을 실행시키고 연결해 놓은 상태에서 진행해야되는 테스트이므로 설정하는 시간도 오래 걸리며 실제 실행 속도도 느리고 자동화하기가 가장 까다롭다. UI 테스트 프레임워크를 사용하여 어느정도 자동화는 가능하지만 아직 100% 자동화하기에는 화면 렌더링이 웹 디자이너가 의도한대로 렌더링 되는지의 여부는 확인하기 어렵다. 그래서 테스트 전략중 가장 낮은 비율을 차지합니다. 프론트엔드 시스템 혹은 백엔드 시스템 각각을 독립적으로 실행한 후 HTTP 클라이언트 툴을 사용하여 테스트하는 방식도 있다. 이는인수 테스트 보다는 간단하지만 실제로 시스템을 실행해서 테스트를 진행해야 하므로 여전히 까다로운 부분이 존재한다.

단위 테스트는 개발자가 테스트 코드를 작성하여 코드로 코드를 테스트하는 방법으로 작성하기 쉬우며 언제든지 실행할 수 있고 실행 속도도 굉장히 빠르기 때문에 100% 자동화가 가능한다. 또한, 자동화와 더불어 디버깅을 도와준다는 장점이 더해져 소프트웨어를 빌드할 때, 사전에 오류 찾아내어 수정할 수 있습. 빌드 전에 단위 테스트를 자동을 수행하는 스크립트를 통해 자동화를 할 수 있으며 이는 빌드 혹은 컴파일 하기 전, 원격 저장소에 코드가 올라가기 전에 검사하여 안정적으로 코드를 관리할 수 있다. 이렇게 디버깅 하기 쉽고 100% 자동화가 가능한 단위 테스트는 시스템 테스트 전략중에 가장 많은 비율을 차지한다.

update: 2023-08-06

댓글 없음:

댓글 쓰기