스크럼 팀을 위한 테스트 전략에 대한 모범 사례

스크럼 개발에서 테스트 계획은 마치 스테로이드 투여와 같은 개념 증명(POC)과 같습니다.

오늘날 많은 성공적인 프로젝트는 소규모의 개념 증명(POC) 단계에서 시작됩니다. POC는 아이디어를 검증하는 초기 단계로, 선택된 기술과 기능이 실제로 작동하는지, 비즈니스 사용자에게 어떤 영향을 줄 수 있는지 평가합니다. 성공적인 POC는 전체 규모의 프로젝트 팀을 구성하여 모든 기능을 갖춘 제품을 설계, 개발, 생산 환경에 배포하는 기반이 됩니다.

스크럼 팀은 이러한 과정에 이상적으로 적합합니다. 각 스프린트마다 상당한 양의 새로운 기능을 추가하여 빠르게 프로토타입을 개발할 수 있으며, 비즈니스 사용자는 실시간으로 개발 과정을 지켜보며 약 10개의 스프린트 내에 아이디어가 구체화되는 과정을 확인할 수 있습니다. 이는 강력한 인상을 주지만(POC의 핵심 목표이기도 함), 한 가지 중요한 특징을 간과하기 쉽습니다. 테스트 활동이 최소화되거나 아예 없을 수 있으며, 테스트 프로세스에 대한 논의조차 무의미하게 여겨질 수 있습니다.

스크럼 팀 내부에서는 테스트를 ‘재미없는’ 활동으로 여길 수 있으며, 사람들은 속도를 늦추는 프로세스 없이 개발하는 것을 선호할 수 있습니다. 테스트 활동은 개발 속도를 늦추는 것처럼 보일 수 있으며, 최종 사용자에게 깊은 인상을 주어야 하는 시기에 속도를 늦추고 싶어하는 사람은 없을 것입니다.

POC 기간이 끝난 후에도 프로젝트 팀이 같은 방식으로 계속 진행하면, 이는 제가 POC를 스테로이드로 비유하는 이유입니다. 생산 시스템의 크기와 기능은 계속 확장되지만 여전히 POC처럼 작동하며, 숨겨진 결함, 탐색되지 않은 코너 케이스, 심각한 충돌을 기다리고 있는 상태입니다.

이러한 상태에서 벗어나기 전까지는 문제 해결이 더욱 복잡해지므로, 팀은 안정적인 릴리스를 유지하기 위해 각 스프린트마다 더욱 어려움을 겪을 것입니다.

다음은 유사한 문제를 해결하는 데 효과적인 것으로 입증된 몇 가지 방법이며, 개발 속도를 저해하지 않으면서도 견고한 테스트 프로세스를 구축하기 위한 모범 사례로 볼 수 있습니다. 이것은 모든 스크럼 팀이 원하는 바일 것입니다.

고통 분산

불필요한 문제를 해결할 때 가장 먼저 해야 할 일은 고통을 분산하는 것입니다.

즉, 여기저기서 개발자의 약간의 추가 활동이 필요하지만, 시간이 지남에 따라 점진적이지만 지속적으로 공동 목표에 기여할 수 있는 계획을 세워야 합니다.

#1. 새로 작성된 모든 코드에 대한 단위 테스트 코드 개발

스크럼 팀이 각 스프린트에서 새로 작성된 모든 코드에 대한 단위 테스트를 완료하도록 설득할 수 있다면, 장기적으로 큰 성과를 얻을 수 있을 것입니다.

그 이유는 분명합니다.

개발자는 코드의 다양한 비정상 경로에 대해 생각해야 합니다.

  • 이러한 단위 테스트는 자동화된 DevOps 파이프라인에 연결되어 개발 또는 테스트 환경에 배포될 때마다 실행될 수 있습니다. 또한, 파이프라인의 메트릭을 쉽게 추출하여 소스 코드에 직접 연결된 테스트 케이스의 적용 범위를 비즈니스 사용자에게 보여줄 수 있습니다.

가장 중요한 것은 가능한 한 빨리 시작하는 것입니다. 단위 테스트 개발이 늦어질수록, 개발자가 스프린트 내에서 이를 추가하는 것이 더 부담스러워집니다.

  • 기존 코드에 대한 단위 테스트를 소급하여 개발하려면 상당한 노력이 필요합니다. 코드의 일부는 다른 개발자가 작성했을 수 있으며, 현재 개발자는 모든 코드 부분이 어떻게 작동해야 하는지에 대한 정확한 지식을 가지고 있지 않을 수 있습니다. 경우에 따라서는 수정된 코드에 단위 테스트를 추가하는 것이, 스프린트(특히 스프린트 계획 단계에서 고려되지 않은) 내에서 기능 변경을 개발하는 것보다 더 많은 시간이 걸릴 수도 있습니다.

#2. 개발 환경에서 모든 단위 테스트 실행 루틴화

새로운 코드를 마스터 브랜치에 병합하기 위한 풀 리퀘스트를 생성하기 전에, 개발 환경에서 기능 코드와 단위 테스트 코드를 모두 테스트하는 것이 표준적인 활동이 되어야 합니다. 이렇게 하면 다음이 보장됩니다.

  • 단위 테스트 코드가 실제로 각 부분에서 작동합니다(결국 확인해야 할 또 다른 코드일 뿐입니다). 이 단계는 종종 완전히 간과됩니다. 단위 테스트가 DevOps 파이프라인에 연결되어 있으면, 어딘가에서 실행되고 테스트될 것이라고 가정하기 때문입니다. 그러나 이는 팀이 모든 커밋된 스토리를 완료하는 데 일반적으로 더 적은 시간과 더 큰 스트레스를 받는 고차원의 스프린트 활동으로 문제를 떠넘기는 것에 불과합니다.
  • 새 기능 코드는 개발자가 핵심 기능을 테스트합니다. 이 테스트를 통해 비즈니스 기능이 완벽하게 검증될 것이라고 기대할 수는 없지만, 적어도 코드가 개발자가 의도한 대로 작동하는지 확인할 수 있습니다(개발 과정에서 비즈니스 로직을 잘못 이해했을 가능성이 있음을 염두에 두어야 함).

#3. 마스터 브랜치에 코드 병합 후 단위 테스트 실행

로컬 브랜치(새로운 기능을 개발하는 사람이 브랜치의 소유자)에서 기능 코드가 작동하는 것과, 풀 리퀘스트를 거쳐 마스터 브랜치에 병합된 후에도 동일한 코드가 작동하는 것은 완전히 다른 문제입니다.

마스터 브랜치에는 다른 스크럼 팀 구성원의 변경 사항이 포함되어 있으며, 충돌이 해결되고 모든 것이 괜찮아 보일지라도 병합과 충돌 해결 후의 코드는 기본적으로 여전히 테스트되지 않은 코드이며, 이를 확인 없이 다음 단계로 넘기는 것은 위험합니다.

따라서 효과적인 방법은 개발 환경에서 이미 수행한 것과 동일한 단위 테스트를, 마스터 브랜치 코드 버전으로 빌드된 환경에서 실행하도록 하는 것입니다.

개발자에게는 삶에 추가해야 할 단계일 수 있지만, 이 경우에는 새로운 것을 발명할 필요 없이 이미 수행한 작업을 다시 실행하기만 하면 되므로 많은 노력이 필요하지 않습니다.

물론, 이 단계는 특정 상황에서 생략될 수 있습니다.

  • DevOps 파이프라인의 자동화된 단위 테스트가 매우 포괄적이라서, 해당 테스트 위에 추가로 수행하는 모든 수동 테스트를 이미 포함하고 있는 경우.

이러한 상태를 달성하는 것은 가능하지만, 실제로는 드문 경우입니다. 개발자가 이렇게 상세하고 자동화된 단위 테스트를 만드는 데 너무 많은 시간을 소비할 수 있기 때문입니다. 제품 소유자가 팀이 이 활동에 많은 시간을 할애하도록 허용하는 것은 쉽지 않을 수 있는데, 이는 스프린트 내에 완료할 수 있는 스토리의 수에 직접적인 영향을 미치기 때문입니다.

그러나 스프린트 콘텐츠에 대한 선호도는 단위 테스트를 수행하지 않거나 최소화하는 변명이 될 수 없습니다. 그렇게 하면 팀은 코드가 단위 테스트 적용 범위가 부족한 상태로 되돌아갈 것이며, 나중에 이를 해결하려 할 때는 이미 늦을 수 있습니다. (단위 테스트 완료에 대한 노력은 실제 스프린트 코드 변경 노력에 비례합니다.)

이러한 이유로, 마스터 코드 버전에서 단위 테스트를 다시 실행하는 것을 주저하지 않고 권장합니다. 이는 그 가치에 비해 매우 적은 노력만 필요로 하기 때문입니다.

이는 릴리스 테스트 단계를 위한 마스터 브랜치의 준비 상태에 대한 최종 확인을 제공하며, 대부분의 기술적인 버그(예: 성공적으로 종료될 때까지 소스 코드가 제대로 실행되지 않는 버그)를 찾는 데 도움이 되므로, 다음 단계에서는 비즈니스 기능 검증에만 집중할 수 있습니다.

기능 테스트 준비

이전의 모든 테스트 활동은 하나의 특정한 결론을 향해 나아갑니다. 마스터 브랜치 코드에 기술적인 버그가 없으며, 엔드-투-엔드 기능 흐름에 문제가 없이 실행 가능하다는 것입니다.

이 단계는 기술적 배경이 없는 한 사람이 쉽게 처리할 수 있습니다.

실제로 개발자와 연결이 끊어진 사람이 테스트를 수행하는 것이 더 좋습니다. 비즈니스 사용자가 코드의 동작을 기대하는 기능을 기능적으로 인식할 수 있다면 더욱 좋습니다. 완료해야 할 두 가지 주요 활동이 있습니다.

#1. 새로운 스프린트 스토리 기능 테스트

각 스프린트는 이전에는 존재하지 않았던 몇 가지 새로운 기능(스프린트 목표 증분)을 가져와 검증해야 합니다. 비즈니스 사용자가 최소한 이전 스프린트 전체에서 기대해 왔던 기능이므로, 새로운 소프트웨어가 비즈니스 사용자가 현재 가지고 있는 것에 만족할 정도로 작동하는지 확인하는 것이 중요합니다.

(오랫동안) 약속된 기능이 마침내 출시되었지만, 제대로 작동하지 않는다는 것을 알게 되는 것은 매우 실망스러운 경험입니다.

따라서 새로운 스프린트 기능을 제대로 테스트하는 것이 중요합니다. 이를 성공적으로 수행하기 위해, 관련된 이해 관계자(제품 소유자 또는 최종 사용자)로부터 중요한 테스트 케이스를 사전에 수집하고, 스프린트 내에서 테스트해야 할 모든 사항을 목록화하는 것이 좋습니다.

언뜻 보기에는 부담스러워 보일 수 있지만, 제 경험상 한 사람이 충분히 관리할 수 있습니다. 대부분의 스프린트가 매우 짧고(예: 2주) 기술 부채 스토리, 문서화, 디자인/스파이크 스토리 등과 같은 추가 활동을 포함하고 있기 때문에 새로운 콘텐츠가 지나치게 많지는 않습니다.

그런 다음, 원하는 기능이 작동하는지 먼저 확인하기 위해 테스트 케이스를 실행합니다. 문제가 발생하면 해당 개발자(결함과 관련된 변경 사항을 담당하는 사람)에게 연락하여 신속하게 문제를 해결할 수 있습니다.

이러한 방식으로 개발자는 기능 테스트에 최소한의 시간을 소비하면서도 자신이 좋아하는 개발 활동에 집중할 수 있습니다.

#2. 회귀 테스트 케이스 실행

기능 테스트의 또 다른 중요한 부분은 지금까지 잘 작동했던 모든 것이 다음 릴리스 후에도 제대로 작동하는지 확인하는 것입니다. 이것이 회귀 테스트의 목적입니다.

회귀 테스트를 위한 테스트 케이스는 각 릴리스 전에 정기적으로 유지 관리하고 검토해야 합니다. 구체적인 프로젝트 세부 사항을 기반으로 단순하게 유지하되, 전체 시스템을 통해 실행되는 대부분의 핵심 기능과 중요한 엔드-투-엔드 흐름을 포함하는 것이 좋습니다.

일반적으로 각 시스템에는 여러 영역에 영향을 미치는 프로세스가 있으며, 이러한 프로세스가 회귀 테스트에 가장 적합한 후보입니다.

경우에 따라 회귀 테스트는 스프린트의 새로운 스토리가 기존 흐름의 특정 부분을 변경하는 경우, 스프린트의 새로운 기능도 간접적으로 테스트할 수 있습니다.

따라서 대부분의 경우 새로운 스프린트 스토리 기능 테스트와 함께 회귀 테스트를 완료하는 것이 어렵지 않습니다. 특히 각 프로덕션 릴리스 전에 정기적으로 수행되고, 프로덕션 릴리스 주기가 너무 짧지 않다면 더욱 그렇습니다.

모든 프로덕션 릴리스 전에 품질 보증 테스트 실행

QA(품질 보증) 테스트는 프로덕션 환경에 출시하기 전의 마지막 단계이며, 종종 중요하지 않다고 여겨져 생략되는 경우가 있습니다. 특히 스크럼 팀이 새로운 콘텐츠를 적극적으로 개발하는 경우에 더욱 그렇습니다.

비즈니스 사용자조차도 새로운 기능에 관심을 보이지만, 기존 기능을 유지하거나 결함 수를 줄이는 데는 큰 관심이 없을 수 있습니다. 그러나 시간이 지남에 따라 이것이 개발 팀의 속도를 늦추는 주요 원인이 되며, 결국 비즈니스 사용자는 원하는 것을 얻지 못하게 될 것입니다.

QA 테스트는 스크럼 팀 외부의 사람들, 이상적으로는 향후 프로덕션 환경에 최대한 가까운 전용 환경에서 비즈니스 사용자가 직접 실행해야 합니다. 또는 제품 소유자가 최종 사용자를 대신하여 테스트를 수행할 수 있습니다.

어쨌든, 이 테스트는 개발 스크럼 팀과 관련 없이 최종 사용자의 관점에서 수행되는 깨끗하고 기능적인 테스트여야 합니다. 제품에 대한 최종적인 관점을 제공하며, 스크럼 팀의 누구도 예상하지 못한 방식으로 사용될 수 있습니다(이상적인 상황은 아니지만 분명히 발생할 수 있는 일입니다). 막바지 수정을 위한 시간이 아직 남아 있습니다.

또는 스크럼 팀이 사용자의 요구 사항을 제대로 이해하지 못했다는 것이 명확해질 수 있으며, 이러한 경우 적어도 실제 프로덕션 릴리스가 이루어지기 훨씬 전에 후속 계획에 동의할 수 있습니다. 이것은 이상적인 상황은 아니지만, 성공적인 프로덕션 릴리스를 발표한 직후에 실패를 인정하는 것보다는 훨씬 낫습니다.

다음 단계는 무엇일까요?

일상적인 스크럼 작업에 이러한 방식을 적용하면, 생산 릴리스를 지연시키거나 전체 스프린트를 다음 릴리스를 준비하는 데 소비하지 않고도, 스크럼 팀의 모든 구성원이 원하지 않는 작업을 강요하지 않고도, 보다 안정적이고 예측 가능한 스프린트 릴리스 습관을 만들 수 있습니다. (대부분의 스크럼 팀원은 이러한 활동을 효과적으로 수행하는 방법을 좋아하지 않거나 모를 수 있습니다.)

그러나 여기서 멈출 필요는 없습니다.

성능 테스트를 추가하는 것도 고려해 볼 만한 주제입니다. 성능 테스트는 종종 무시되거나 불필요한 것으로 간주되어 ‘스크럼 활동 최적화’의 첫 번째 단계에서 제외되기도 합니다. 그러나 성능을 정기적으로 확인하지 않으면 프로덕션 시스템이 시간이 지남에 따라 어떻게 발전할지 항상 의문을 갖게 됩니다.

한 단계 더 나아가 자동화된 테스트를 도입할 수도 있습니다.

이미 자동화된 테스트(파이프라인의 단위 테스트)를 다루었지만, 테스트 환경에 배포할 때마다 완전히 자동화되어 자체적으로 실행되는 엔드-투-엔드 회귀 테스트를 개발할 수 있습니다. 이것은 개발 스크럼 팀의 부담을 크게 줄여줄 수 있지만, 이러한 자동화된 테스트를 개발하고 유지 관리하기 위한 전담 팀이 필요합니다. 프로덕션 코드가 변경될 때마다 기존 자동화 테스트가 유효하지 않게 될 수 있으므로, 파이프라인에서 계속 작동하도록 하려면 업데이트가 필요합니다. 이는 일부 조직에서만 기꺼이 비용을 지불하려는 노력이지만, 개발 스크럼 팀에는 큰 이점을 가져다줄 수 있습니다.

이러한 주제는 이 문서의 범위를 훨씬 넘어서며, 여기에 언급된 각 테스트 유형에 대한 올바른 일정과 타이밍을 계획하여 스프린트 기간 내에 수행할 수 있도록 하는 것이 중요합니다. 다음에 기회가 되면 이 주제에 대해 더 자세히 다뤄보겠습니다!