들어가기 앞서
본 포스팅은 해당 글을 번역 한 글입니다. 어느 정도의 의역이 있을 수 있습니다.
https://thenewstack.io/unit-tests-are-overrated-rethinking-testing-strategies/
단위 테스트는 과대평가되었습니다: 테스트 전략 다시 생각하기
성공적이고 지속적인 테스트 전략을 위해서는 다양한 유형의 테스트 간에 신중한 균형이 필요합니다. 이 문서에서는 그 방법을 설명합니다.
업계는 릴리스 주기를 단축하기 위해 노력하고 있고, 이에 따라 릴리스되는 코드의 품질에 대한 신뢰를 유지하는 데 어려움을 겪고 있습니다. 이는 성공적인 지속적인 테스트 전략의 근본적인 필요성을 강조합니다.
많은 기업이 DevOps와 지속적 배포에 집중하고 있지만, 안타깝게도 소프트웨어 릴리즈 트렌드는 상대적으로 제자리걸음을 하고 있으며, 적어도 매일 릴리즈하는 팀은 10%에 불과합니다. 시프트레프트(예: 단위 테스트 더 많이 작성하기), 시프트라이트(예: 프로덕션 환경에서 테스트하기), 수동 테스트에서 자동화된 테스트로 전환, 심지어 명확한 테스터라는 역할을 두지 않고 개발자가 본인이 작성하는 코드의 품질에 대한 책임을 지도록 하는 등 여러 가지 전략이 배포되고 있습니다.
이러한 테스트 전략은 잘 되는 경우도, 잘 되지 않는 경우도 있으며 기술 수준, 성숙도, 문화에 따라 팀마다 그 정도가 다를 수 있습니다. 테스트가 릴리스를 지연시키는 경우가 많은데, 이는 팀이 디지털 신뢰의 가장 중요한 요소인 최적화에 집중하지 않거나 집중할 동기를 부여받지 못하기 때문입니다.
단위 테스트(작은 코드 조각을 검사하여 정보를 조기에 자주 전달하는 프로세스)는 지금까지 모범 사례로 여겨져 왔으며, 개발자가 오류를 빠르게 발견할 수 있기 때문에 단위 테스트가 개발 중에 가장 큰 가치를 제공한다는 주장에 의해 뒷받침되기도 합니다.
이 아이디어가 널리 받아들여지면서 '단위 테스트'라는 용어는 이제 일반적으로 자동화된 테스트와 혼용되어 그 의미를 일부 상실하고 혼란을 야기하고 있습니다.
테스팅은 모노리스가 아닙니다
먼저, 테스트의 유형을 헷갈리기 쉽고 혼란을 야기할 수 있으므로 작성되는 테스트 유형을 구분하는 것이 중요합니다. 이 문서에서는 기능이 올바르게 작동하는지 확인하는 기능 테스트에 중점을 두며, 이는 접근성 테스트, 성능 테스트, 보안 테스트 및 부하 테스트와는 다릅니다.
기능 테스트에는 크게 두 가지 용도가 있습니다: 새 기능이나 버그 수정이 의도한 대로 작동하는지 확인하는 인수 테스트와 새 코드가 이전 코드를 손상시키지 않았는지 확인하기 위해 정기적으로 실행하는 회귀 테스트가 있습니다.
개발자는 일반적으로 클래스의 각 메소드에 대해 가능한 모든 다양한 입력과 같이 가장 저수준의 코드를 검증하는 단위 테스트로만 구성된 인수 테스트에 중점을 둡니다. 애자일 환경에서는 개발자가 먼저 테스트를 작성한 다음 해당 테스트가 통과하도록 기능을 구현하는 테스트 주도 개발(TDD)을 통해 이 작업을 수행하는 경우가 많습니다. 테스트 가능한 코드를 작성하는 것이 실제 테스트보다 훨씬 더 중요하기 때문에 TDD 자체도 과대평가되고 있습니다.
인수 테스트에는 공통 기능을 공유하는 코드 집합을 분리하여 제대로 작동하는지 확인하는 구성 요소 테스트가 점점 더 많이 포함되고 있으며, 다양한 구성 요소가 서로 제대로 상호 작용하는지 확인하는 통합 테스트도 포함되기도 합니다. 별도의 QA 또는 테스트 팀이 없는 팀이나 부서의 경우, 승인 테스트에는 엔드 투 엔드(E2E) 테스트 또는 사용자 인터페이스(UI) 테스트와 같은 덜 정확한 용어로 더 자주 언급되는 D2D(DOM-데이터베이스) 테스트가 포함될 수 있습니다. D2D 테스트는 최종 사용자가 UI, API, 서비스 레이어, 데이터베이스를 거쳐 다시 데이터베이스에 이르는 전체 스택을 평가합니다.
인수 테스트를 회귀 테스트로 사용할 때 문제가 발생합니다. 이는 애자일 컨설턴트가 이해관계자 간의 커뮤니케이션을 장려하기 위해 종종 지지하는 프로세스인 행위 주도 개발(BDD)의 실제 약속이며, 실제로는 프로세스에 복잡성을 더할 수 있지만 모든 사람이 테스트에 동의한 다음 사용하는 프로세스입니다.
테스팅 피라미드
테스팅 피라미드는 기능 회귀 테스트에 접근하는 방법에 대한 일반적인 지침입니다. 이 피라미드에서는 단위 테스트를 가장 아래에, 통합 테스트를 중간에, D2D 테스트를 가장 위에 배치합니다. 단위 테스트가 더 빠르고 안정적이기 때문에 단위 테스트에 가장 중점을 두어야 하는 반면, D2D 테스트는 가장 덜 중점을 두어야 하며(훨씬 느리고 훨씬 더 허술합니다) 통합 테스트는 그 중간 어딘가에 위치해야 한다는 이유에서입니다.
이 접근 방식의 한 가지 문제점은 테스터와 개발자의 역할을 보다 명확하게 분리하는 조직에서는 중간 계층이 사실상 무시된다는 것입니다. 개발자는 단위 테스트 커버리지 비율 메트릭으로 평가받기 때문에 단위 테스트에 집중합니다. 이러한 테스트는 충분하지 않습니다. 테스터는 전통적으로 테스트가 수행되어 온 방식이기 때문에 UI에 대한 입력에 집중합니다. 이러한 테스트는 부실하게 수행되기 쉬우며, 결국 테스트를 작성해야 하는 모든 사람이 어려움을 겪게 됩니다.
또 다른 문제는 테스트 피라미드가 적절한 측정 수치(메트릭)를 기반으로 하지 않는다는 것입니다. 정기적으로 업데이트되는 웹사이트를 테스트해 본 사람이라면, 테스트를 짜고 실행하는 것보다 유지보수하는 것이 더 비용이 많이 든다는 것을 알고 있습니다.
그렇기 때문에 인공지능 프로젝트에서 기본 테스트를 만드는 것은 사람들이 생각하는 것만큼 인상적인 성과가 나오지 않습니다. 속도는 올바른 측정 기준이 아니며, 속도를 비교하는 것은 잘못된 비용에 초점을 맞추고 있는 것입니다. 테스트를 유지하는 데 필요한 리소스의 양에 대한 신뢰도가 측정 기준이 되어야 합니다.
단위 테스트는 대부분의 사람들이 생각하는 것보다 이 지표(테스트를 유지하는 데에 필요한 리소스)에 훨씬 더 열악합니다. 첫 번째 문제는 테스트가 시스템의 실제 상태에 대해 유용한 정보를 제공하지 못하는 경우가 많다는 것입니다. 단위 테스트가 인수 테스트로 작성되는 경우 특정 구현과 복잡하게 결합되어 있는 경우가 많습니다.
이러한 단위 테스트는 구현이 변경될 때에만 실패하며, 변경으로 인해 시스템이 중단되는 경우(예: 클래스 상수의 값 확인)에는 실패하지 않습니다. 인수 테스트를 회귀 테스트로 사용하는 것은 의도적으로 신중하게 수행해야 하며, 시스템 동작에 대한 유용한 정보를 제공하지 않는 모든 것을 삭제해야 합니다.
단위 테스트의 또 다른 큰 문제점은, 한 메서드의 입력을 테스트하기 위해 다른 메서드의 응답을 모킹해야 하는 경우가 많다는 점입니다. 이러면 더 이상 현재 가지고 있는 시스템을 테스트하는 것이 아니라 과거에 가지고 있다고 가정한 시스템을 테스트하는 것입니다. 실제로는 더 이상 제공되지 않는 입력값이 수신될 것이라고 가정했기 때문에 시스템은 중단될 지라도 단위 테스트는 실패하지 않습니다. 모킹을 수행하기에 가장 좋은 곳은 통합 계층(integration layer)에서 별도의 테스트 세트로 인터페이스의 양쪽을 모킹하고 컨트랙트 테스트를 사용하여 이러한 모킹이 양쪽에서 시스템의 실제 상태를 올바르게 나타내는지 확인할 수 있는 곳입니다. 또한 다른 회사가 소유한 서비스를 모킹하는 것도 좋은 방법이며, 특히 그 다른 회사의 서비스의 API가 안정적일 경우 더욱 좋은 방법입니다.
이러한 것들 때문에 실제로 단위 테스트는 실행 속도는 빠르지만 유지 관리가 쉽지만은 않습니다. 제품이 변경될 때마다 개발자는 테스트 스위트에서 모의 테스트를 통해 모든 테스트가 여전히 적용되는지 부지런히 살펴봐야 합니다. 그런 다음 구현의 변경으로 인해 중단되는 테스트는 향후 회귀를 감지하는 데 쓸모없는 테스트로 대체되는 경우가 많더라도 업데이트해야 합니다.
용이성보다는 자신감을 위한 테스트
단위 테스트는 많은 사람이 소프트웨어 개발 모범 사례의 초석으로 여기지만, 모든 테스트 요구 사항을 충족하는 만병통치약은 아닙니다. 업계가 진화하고 더 짧은 릴리스 주기를 지향함에 따라 테스트에 대한 접근 방식도 진화해야 합니다. 성공적이고 지속적인 테스트 전략을 위해서는 다양한 유형의 테스트 간에 신중한 균형이 필요하며, 팀은 테스트의 실행 속도에만 초점을 맞추는 대신 각 테스트가 정확성을 유지하는 데 투자한 시간과, 노력에 비해 제공하는 신뢰도에 우선순위를 두어야 합니다.
보다 총체적인 테스트 접근 방식을 수용함으로써 팀은 더 나은 소프트웨어를 더 빠르게 제공할 수 있습니다. 인생의 많은 부분이 그렇듯이, 핵심은 현재 가장 편리한 도구가 아니라 업무에 적합한 도구를 사용하는 것입니다. 테스트에 있어서는 스마트하고 전략적인 방법이 항상 무차별적인 방법을 이깁니다.
'개발 일반 > 테스트 코드' 카테고리의 다른 글
사내 세미나 - 테스트 코드에 대해 알아보자 (0) | 2023.05.22 |
---|---|
Jest로 Frontend 테스팅 할 때 힘들었던 점들 정리 (0) | 2023.04.13 |