10개의 자격증을 보유했지만 버그를 찾아내는 테스트를 단 하나도 작성하지 못한 테스터
요약
자격증 보유와 실제 버그를 찾아내는 능력 사이의 간극을 지적합니다. 단순한 요구사항 충족을 넘어, 가설을 세우고 시스템의 결함을 조사하는 '버그 사냥꾼'으로서의 사고방식이 중요함을 강조합니다.
핵심 포인트
- 자격증은 지식과 어휘를 제공하지만 버그를 찾는 사고력을 보장하지 않음
- 단순히 통과하는 테스트(Happy Path)와 결함을 증명하는 테스트의 차이
- 테스트를 체크리스트가 아닌 하나의 조사(Investigation) 과정으로 접근해야 함
당신은 ISTQB Foundation을 가지고 있습니다. ISTQB Advanced도 있고, Certified ScrumMaster도 있습니다. 클라우드 자격증도 있고, 보안 테스팅 자격증도 있습니다. 아마 어떤 플랫폼에서 받은 테스터를 위한 Python 배지도 있을지 모릅니다.
그런데도 당신은 여전히 실제 버그를 찾아내는 테스트를 작성하지 못합니다.
지난 분기에 당신과 같은 사람을 인터뷰했습니다. 이력서는 약어(acronyms)의 벽이었습니다. 대화는 이론의 벽이었습니다. "저는 V-모델 (V-model)을 따릅니다." "동등 분할 (equivalence partitioning)을 사용합니다." "시프트 레프트 (shift-left)를 믿습니다."
그때 제가 물었습니다. "개발자가 놓친 무언가를 잡아낸, 당신이 작성한 테스트를 하나만 보여주세요."
침묵이 흘렀습니다.
긴장해서가 아니었습니다. 버그를 찾아내는 테스트를 작성해 본 적이 없었기 때문입니다. 그들은 통과하는 테스트를 작성해 왔습니다. 요구사항을 충족하는 테스트를 작성해 왔습니다. 무언가를 망가뜨리는 테스트는 단 한 번도 작성해 본 적이 없었습니다.
그것이 자격증 보유자와 테스터의 차이입니다.
자격증은 당신의 기억력을 테스트합니다. 버그는 당신의 사고력을 테스트합니다.
제가 무엇을 의미하는지 보여드리겠습니다.
자격증의 함정 (The Certification Trap)
자격증이 쓸모없는 것은 아닙니다. 자격증은 당신에게 어휘를 제공합니다. 구조를 제공합니다. 채용 담당자들이 테스트 케이스 (test case)가 무엇인지 아느냐고 묻지 않도록 LinkedIn에 올릴 무언가를 제공합니다.
하지만 자격증은 버그를 찾는 방법을 가르쳐주지 않습니다.
그 이유는 다음과 같습니다. 모든 자격증 시험은 알려진 지식을 테스트합니다. 당신은 실라버스 (syllabus)를 공부합니다. 정의를 암기합니다. 경계값 분석 (boundary value analysis)에 관한 객관식 질문에 답합니다. 그리고 합격합니다.
그다음 당신은 애플리케이션 앞에 앉습니다. 애플리케이션에는 실라버스가 없습니다. 문서에는 경계값 분석 섹션이 없습니다. 애플리케이션에는 로그인 양식이 있을 뿐입니다. 이 양식은 가끔 명백히 틀린 비밀번호로도 로그인을 허용하곤 합니다. 하지만 오직 화요일에만, 그리고 서버 시계가 정확히 4분 뒤처져 있을 때만 가능합니다.
어떤 자격증도 당신을 그런 상황에 대비시키지 않습니다.
10개의 자격증을 가진 테스터는 테스팅을 체크리스트처럼 다룹니다. 그들은 요구사항으로부터 테스트 케이스를 작성합니다. 그것들을 실행합니다. 통과(pass) 또는 실패(fail)를 표시합니다. 커버리지 지표 (coverage metrics)를 보고합니다.
버그를 찾아내는 테스터는 테스트를 하나의 조사(investigation)처럼 다룹니다. 그들은 가설(hypothesis)에서 시작합니다. 애플리케이션이 틀렸음을 증명하려고 시도합니다. 그들은 이상한 점(weirdness)을 추적합니다.
진짜 버그를 찾아내는 테스트란 어떤 모습인가
코드의 차이를 보여드리겠습니다.
다음은 자격증 공부는 했지만 버그를 사냥하는 법은 배우지 못한 사람이 작성한 전형적인 테스트입니다:
import { test, expect } from '@playwright/test';
test('user can complete checkout with valid credit card', async ({ page }) => {
...
이 테스트는 통과(pass)합니다. 해피 패스(happy path)를 커버합니다. 모든 것이 완벽할 때 기능이 작동함을 증명합니다.
하지만 이 테스트는 절대 버그를 찾아내지 못할 것입니다.
이제 버그 사냥꾼처럼 생각하는 사람이 작성한 테스트를 보겠습니다:
import { test, expect } from '@playwright/test';
test('checkout rejects card number with typo in first digit', async ({ page }) => {
...
두 번째 테스트가 더 복잡한 것은 아닙니다. 더 의심스럽게(suspicious) 작성되었을 뿐입니다. 애플리케이션이 실패할 것이라고 가정합니다. 에러(error)를 확인합니다. 또한 성공 상태(success state)가 실수로 나타나지 않았는지도 확인합니다.
이것이 사고방식(mindset)입니다. "작동하는가?"가 아니라 "어디서 깨지는가?"를 묻는 것입니다.
진짜 격차: 당신은 테스트 실패를 경험해 본 적이 없다
제가 직접 대화하고 있는 독자분들에게 솔직한 진실을 말씀드리겠습니다. 3년의 경력과 자격증을 쌓아온 테스터인 당신 말입니다. 당신은 예상치 못한 이유로 실패하는 테스트를 단 한 번도 작성해 본 적이 없습니다.
환경(environment)이 다운되어 테스트가 실패하는 것을 보았습니다. 데이터가 변경되어 테스트가 실패하는 것을 보았습니다. 누군가 로케이터(locator)를 업데이트해서 테스트가 실패하는 것을 보았습니다.
하지만 애플리케이션 로직(logic)에서 이전에 알지 못했던 실제 결함(defect)을 발견하여 테스트가 실패하는 경우는 단 한 번도 작성해 본 적이 없습니다.
그것이 당신의 커리어 격차(career gap)입니다. 이력서의 공백이 아니라, 경험의 격차입니다.
그리고 그 어떤 자격증으로도 이 격차를 채울 수 없습니다.
격차를 줄이는 방법
실패하도록 설계된 테스트를 작성함으로써 그 격차를 줄일 수 있습니다.
플래키 테스트(flaky tests)가 아닙니다. 타이밍(timing) 때문에 실패하는 테스트도 아닙니다. 애플리케이션에 버그가 있어서 실패하는 테스트를 작성하십시오.
제가 멘토링하는 모든 테스터에게 주는 연습 과제는 다음과 같습니다. 현재 애플리케이션의 기능 중 하나를 선택하십시오. 그 기능을 망가뜨리려는 테스트를 작성하는 데 한 시간을 할애하십시오. 기능이 작동함을 확인하는 테스트가 아닙니다. 기능이 올바르게 망가지는지 확인하는 테스트를 작성하십시오.
검색 기능의 경우, "유효한 쿼리에 대해 검색이 결과를 반환한다"를 테스트하지 마십시오. 대신 "의미 없는 문자열(gibberish)에 대해 검색이 0개의 결과를 반환한다", "검색이 SQL 인젝션 (SQL injection) 문자를 처리할 때 충돌(crash)이 발생하지 않는다", "빈 문자열로 검색했을 때 500 에러 대신 도움이 되는 메시지를 보여준다"를 테스트하십시오.
파일 업로드 기능의 경우, "사용자가 유효한 PDF를 업로드할 수 있다"를 테스트하지 마십시오. 대신 "../../../etc/passwd라는 이름의 파일을 업로드해도 시스템 파일이 덮어쓰여지지 않는다", "2GB 파일을 업로드할 때 업로드가 시작되기 전에 크기 오류를 보여준다", "확장자가 없는 파일을 업로드해도 미리보기 생성기(preview generator)가 충돌하지 않는다"를 테스트하십시오.
이러한 테스트들을 작성하고 실행하십시오. 테스트가 실패하면 버그를 찾은 것입니다. 테스트가 통과하면 애플리케이션이 예외 케이스(edge cases)를 올바르게 처리한다는 것을 증명한 것입니다. 어느 쪽이든 여러분은 무언가를 배우게 됩니다.
내 생각을 바꾼 코드
저는 수년 동안 무언가에 대해 잘못 알고 있었습니다. 저는 좋은 테스트 자동화(test automation)란 모든 요구사항을 통과하는 테스트로 커버하는 것이라고 생각했습니다. 성공의 척도를 통과된 빌드(green builds)로 측정했습니다.
그러다 핀테크 팀에서 결제 시스템을 작업하게 되었습니다. 우리는 95%의 테스트 커버리지(test coverage)를 보유하고 있었습니다. 모든 테스트는 통과되었습니다. 하지만 시스템이 프로덕션(production)에 배포된 후, 누군가 알아차리기 전까지 3일 동안 돈을 잃었습니다.
버그는 반올림 계산에 있었습니다. 총액이 $10.005와 같을 때, 시스템은 고객에게는 내림을 적용하고 가맹점에게는 올림을 적용했습니다. 차액은 거래당 몇 센트 수준이었습니다. 하지만 수천 건의 거래가 쌓이자 그것은 실제 큰 돈이 되었습니다.
우리의 테스트는 해피 패스(happy path)를 커버했습니다. 새드 패스(sad path)도 커버했습니다. 하지만 "소수점 수학 계산이 틀리면 어떻게 될까"라는 경로는 커버하지 못했습니다. 아무도 그런 테스트를 작성할 생각을 하지 못했기 때문입니다.
그 사건 이후, 저는 테스트를 작성하는 방식을 바꿨습니다. 이제 모든 테스트는 하나의 질문으로 시작합니다: "이 기능이 조용히 실패(fail silently)하려면 어떤 조건이 참이어야 하는가?"
다음은 그러한 사고방식을 보여주는 Python 예시입니다:
import pytest
from decimal import Decimal
...
이 테스트는 첫 번째 버전에서는 아무것도 찾아내지 못했습니다. 개발자들은 올바른 반올림 (rounding) 로직을 작성했었습니다. 하지만 우리가 소수점 자릿수가 다른 새로운 통화를 추가했을 때, 이 테스트는 첫 한 시간 만에 버그를 잡아냈습니다. 테스트는 이미 작성되어 있었고, 이미 실행 중이었습니다. 그리고 즉시 실패했습니다.
그것이 바로 버그를 찾아내도록 설계된 테스트의 가치입니다. 테스트는 그 자리에 머물며 코드가 변경되기를 기다리다가, 회귀 (regression)가 프로덕션 (production)에 도달하기 전에 이를 잡아냅니다.
이번 주에 해야 할 일
당신은 자격증을 가지고 있습니다. 경력도 있습니다. 하지만 증거는 없습니다.
여기 한 가지 행동 지침이 있습니다. 포트폴리오 사이트를 만들지 마세요. LinkedIn을 업데이트하지 마세요. 또 다른 자격증을 위해 공부하지 마세요.
실패하도록 설계된 테스트를 하나 작성하세요. 무언가가 작동함을 검증하는 테스트가 아닙니다. 무언가가 고장 났음을 증명하려는 테스트를 작성하세요.
그것을 실행하세요. 만약 통과한다면, 당신은 안전 보장 (safety guarantee)을 문서화한 것입니다. 만약 실패한다면, 당신은 버그를 찾아낸 것입니다. 어느 쪽이든, 당신은 보여줄 수 있는 실질적인 무언가를 갖게 됩니다.
그 내용을 기록하세요. 세 단락이면 충분합니다. 무엇을 테스트했는지, 어떻게 테스트했는지, 그리고 무엇을 발견했는지 말입니다. 그것이 당신의 포트폴리오입니다. 그것이 당신이 사고할 수 있다는 증거입니다.
다음에 누군가가 버그를 잡아낸 테스트를 보여달라고 요청할 때, 당신은 답을 가지고 있을 것입니다.
자격증이 아니라, 답을 말이죠.
당신이 버그를 찾을 수 있다는 것을 증명하기 위해 이번 주에 작성할 단 하나의 테스트는 무엇입니까?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기