개념
실험실에서 시약이 오염되면 어떤 실험도 결과를 못 믿는다. 장비가 좋아도, 절차가 정확해도 그렇다. 테스트 데이터가 그 시약이다.
그래서 이 레슨은 레슨 1의 케이스에서 가장 많이 비는 칸인 사전 조건을 실제로 만들어 내는 방법을 다룬다. "VIP 등급이고 쿠폰이 2개인 계정" 이라는 사전 조건은 적는 데 10초지만, 그 계정을 매번 만들어 내는 것이 실무에서 테스트를 가장 많이 멈추는 일이다.
왜 테스트 데이터가 문제가 되는가
테스트를 실행할 때마다 "이 계정에 주문 내역이 있어야 하는데 없다", "어제는 됐는데 오늘은 이 데이터가 사라졌다" 같은 문제를 겪어본 적이 있다면, 그건 테스트 로직이 아니라 테스트 데이터 관리의 문제다. 데이터가 불안정하면 그 위에서 도는 어떤 테스트도 신뢰할 수 없다.
막히는 모습은 네 가지로 정리된다.
| 증상 | 실제 원인 |
|---|---|
| 없다 | 조건에 맞는 계정·데이터를 아무도 만들어 두지 않았다 |
| 오염됐다 | 지난 테스트가 값을 바꿔 놓고 되돌리지 않았다 |
| 변해 버렸다 | 시간이 지나 쿠폰이 만료되고 구독이 끝났다 |
| 남이 썼다 | 다른 사람이 같은 계정으로 동시에 테스트했다 |
세 번째가 가장 조용하다. 어제까지 되던 테스트가 오늘 깨지는데 코드는 아무것도 안 바뀌었다. 원인이 "쿠폰 유효기간이 어제 지났다" 인 것을 알아내는 데 반나절이 간다.
어떤 데이터가 필요한지 먼저 적는다
데이터를 만들기 전에 목록으로 정리한다. 레슨 1의 사전 조건을 모으면 그 목록이 거의 완성된다.
| 항목 | 예 |
|---|---|
| 계정 종류 | 신규 가입 / 일반 / VIP / 관리자 / 휴면 / 탈퇴 |
| 데이터 상태 | 주문 0건 / 주문 여럿 / 부분 환불 이력 |
| 보유물 | 쿠폰 0·1·여러 장 / 포인트 0·소액·거액 |
| 경계 데이터 | 이름 최대 길이 / 이모지 / 금액 0·최대 |
| 예외 상태 | 결제 실패 이력 / 권한 회수된 계정 |
이 표를 한 번 만들어 공유하는 것만으로 팀의 시간이 줄어든다. 사람마다 매번 계정을 새로 만드는 일이 없어지기 때문이다.
접근 1 — 합성 데이터(Synthetic Data)
실제 운영 데이터를 쓰지 않고, 테스트 목적에 맞게 처음부터 만들어낸 데이터다. 장점은 개인정보 위험이 없고, 원하는 조건(예: "쿠폰이 3개 있고 등급이 VIP인 사용자")을 정확히 맞출 수 있다는 것이다. 단점은 실제 데이터의 지저분함(빈 값, 이상한 형식, 예상 못 한 조합)을 못 재현할 수 있다는 것이다.
합성 데이터를 만드는 방법은 세 가지이고, 보통 섞어 쓴다.
| 방법 | 어떻게 | 적합한 때 |
|---|---|---|
| 손으로 만들기 | 화면에서 직접 가입·주문 | 케이스 몇 개, 초기 단계 |
| 생성기 사용 | 라이브러리로 이름·주소·카드번호 생성 | 양이 필요할 때 |
| 코드 팩토리 | 함수 하나로 "VIP + 쿠폰 2장" 생성 | 자동화와 함께(모듈 13 레슨 10) |
세 번째가 가장 값이 크다. createVipUserWithCoupons(2) 같은 함수
하나를 만들어 두면, 그 조건이 필요한 모든 테스트가 그것을 쓴다. 조건이
바뀌어도 한 곳만 고치면 된다.
합성 데이터에는 지저분함을 일부러 넣는다
합성 데이터의 약점이 너무 깨끗한 것이다. 홍길동, 010-1234-5678,
서울시 강남구 만 넣으면 운영에서 깨지는 값을 영원히 못 만난다.
목록에 아래를 섞어 둔다.
- 이름: 한 글자, 아주 긴 이름, 공백 포함, 영문·한자 혼용, 이모지
- 주소: 번지 없는 주소, 아주 긴 상세주소, 줄바꿈 포함
- 금액: 0원, 1원, 소수점, 아주 큰 금액
- 날짜: 2월 29일, 월말, 미래 날짜
- 상태: 중간에 끊긴 주문, 부분 환불, 데이터가 반쯤 만들어진 계정
마지막 줄이 가장 안 만들어진다. 실제 운영에는 "가입은 했는데 인증은 안 끝난" 같은 중간 상태가 수없이 있고, 화면에서 정상 흐름으로 만들면 그 상태가 생기지 않는다. 직접 데이터를 넣어야 재현된다.
접근 2 — 운영 데이터 마스킹(Data Masking)
실제 운영 데이터를 복사해오되, 이름·이메일·전화번호·주민번호 같은 민감정보를 가짜 값으로 치환해서 쓰는 방식이다. 실제 데이터의 지저분함을 그대로 재현할 수 있다는 장점이 있지만, 마스킹이 불완전하면 개인정보 유출 사고로 이어질 수 있어 각별히 주의해야 한다.
이름을 "홍길동"으로 일괄 치환해도, 주소나 결제 내역 같은 다른 필드에 개인을 특정할 수 있는 정보가 남아있다면 마스킹이 완전하지 않은 것이다.
마스킹 기법은 몇 가지로 나뉘고, 필드마다 다른 기법을 쓴다.
| 기법 | 예 | 주의 |
|---|---|---|
| 치환 | 이름 → 무작위 가명 | 참조 무결성이 깨질 수 있다 |
| 섞기(셔플) | 같은 열의 값을 서로 바꿈 | 분포는 유지되지만 조합으로 추정 가능 |
| 부분 가림 | 010-****-5678 | 남긴 부분으로 식별될 수 있다 |
| 일반화 | 생년월일 → 출생 연도, 주소 → 시·구까지 | 재식별 위험을 크게 낮춘다 |
| 삭제 | 주민번호 열 자체를 비움 | 그 필드를 쓰는 기능은 테스트 불가 |
| 토큰화 | 같은 값을 같은 가짜 값으로 치환 | 참조 무결성을 지킨다 |
토큰화가 실무에서 가장 유용하다. 회원 테이블의 이메일과 주문 테이블의 이메일을 서로 다른 가짜 값으로 바꾸면 연결이 끊겨 데이터가 쓸모없게 된다. 같은 입력을 항상 같은 출력으로 바꾸면 관계가 유지된다.
마스킹에서 가장 많이 놓치는 것
필드 단위로 가려도 다른 경로로 개인이 드러난다.
- 조합으로 특정된다 — 성별·생년·거주 시군구 셋이면 상당수가 특정된다
- 드문 값이 남는다 — 희귀 질환명, 특정 직업, 아주 큰 거래 금액
- 자유 입력란 — 배송 메모에 이름과 전화번호가 적혀 있다
- 첨부와 로그 — 이미지, 서버 로그, 감사 로그는 마스킹 대상에서 빠진다
- 백업 — 마스킹 전 덤프 파일이 공유 폴더에 남는다
세 번째와 다섯 번째가 실제 사고의 단골이다. 구조화된 필드만 보고 "마스킹 완료" 로 결론 내리면, 자유 입력란에 든 원문이 그대로 나간다.
국내 맥락 — 가명처리와 익명처리
한국에서는 개인정보보호법이 가명처리와 익명처리를 구분한다. 용어를 알아 두면 보안·법무와 대화가 된다.
| 구분 | 뜻 | 테스트에서 |
|---|---|---|
| 가명처리 | 추가 정보를 쓰면 다시 식별 가능 | 여전히 개인정보로 관리해야 한다 |
| 익명처리 | 다시 식별 불가능 | 개인정보가 아니게 된다 |
실무에서 마스킹한 운영 데이터는 대개 가명처리 수준이다. 그러면 개인정보로서 관리 대상이라는 뜻이고, 접근 권한·보관 기간·반출 통제가 그대로 적용된다. "마스킹했으니 괜찮다" 는 결론이 성립하지 않는 이유다.
그래서 많은 조직이 운영 데이터 복제를 아예 금지하고 합성 데이터만 쓴다. 번거롭지만 사고 위험을 원천에서 없애는 선택이다. 어느 쪽인지는 조직의 정책을 먼저 확인한다 — QA가 혼자 판단할 일이 아니다.
접근 3 — 시딩(Seeding)과 리셋(Reset)
테스트를 실행하기 전에 필요한 데이터를 스크립트로 미리 넣어두는 것을 시딩이라 하고, 테스트가 끝난 후 데이터를 원래 상태로 되돌리는 것을 리셋이라 한다.
[리셋: 초기 상태로] → [시딩: 필요한 데이터 주입] → [테스트 실행] → [리셋]이 사이클이 안정적이어야 "어제는 됐는데 오늘은 안 된다"는 재현 불가능한 실패(모듈 5 레슨 12와 연결)를 줄일 수 있다. 시딩·리셋이 불안정하면 테스트 실패의 원인이 코드 결함인지 데이터 오염인지 구분하기 어려워진다.
리셋을 어떻게 하나 — 네 가지 방식
리셋의 방식에 따라 속도와 신뢰도가 크게 다르다.
| 방식 | 어떻게 | 속도 | 믿을 만한가 |
|---|---|---|---|
| 트랜잭션 롤백 | 테스트를 트랜잭션으로 감싸고 되돌림 | 가장 빠름 | 높다. 단 커밋이 섞이면 못 쓴다 |
| 삭제 스크립트 | 만든 데이터를 지우는 쿼리 | 빠름 | 지우는 걸 빠뜨리기 쉽다 |
| 스냅샷 복원 | DB를 초기 상태 이미지로 되돌림 | 느림 | 가장 확실하다 |
| 매번 재생성 | 컨테이너·DB를 새로 띄움 | 가장 느림 | 가장 확실하다 |
두 번째가 실무에서 가장 많이 쓰이면서 가장 많이 샌다. 주문을 지웠는데 주문 상세·결제 이력·포인트 기록이 남는 식이다. 지울 때는 만든 것의 역순 으로, 연관 테이블까지 따라가야 한다.
그래서 삭제보다 "새로 만들기" 가 안전하다. 매 테스트가 자기 계정을 새로 만들어 쓰면 지울 것이 없고, 남은 데이터는 주기적으로 일괄 정리한다.
데이터 격리(Isolation)
여러 사람 또는 여러 자동화 테스트가 동시에 같은 데이터베이스를 쓰면, 한쪽이 만든 데이터를 다른 쪽이 지우거나 바꿔서 서로 간섭할 수 있다. 테스트마다 독립된 데이터(별도 계정, 별도 스키마, 트랜잭션 롤백 등)를 쓰도록 격리하는 것이 안정적인 테스트의 전제조건이다.
격리에는 수준이 있고, 비용이 다르다.
| 수준 | 방법 | 비용 | 막아 주는 것 |
|---|---|---|---|
| 계정 단위 | 테스트마다 새 계정을 만든다 | 가장 낮다 | 사람·테스트 간 간섭 대부분 |
| 데이터 접두사 | 만드는 데이터 이름에 t-20261005-a3 식 표시 | 낮다 | 누가 만든 것인지 식별 |
| 스키마 분리 | 실행마다 별도 스키마 | 중간 | 전역 설정 간섭까지 |
| 환경 분리 | 사람마다 독립 환경 | 높다 | 거의 전부 |
첫 줄이 가장 가성비가 높다. 공용 계정 하나를 여러 사람이 쓰는 것이 간섭의 최대 원인이고, 테스트마다 계정을 새로 만들면 그 대부분이 사라진다.
두 번째 줄의 식별 접두사는 작은 습관인데 효과가 크다. 테스트가 만든 데이터에 표시가 있으면 운영 데이터와 섞여도 골라낼 수 있고, 일괄 정리도 쉽다. 모듈 13 레슨 10에서 자동화에 적용하는 방식이 이것이다.
주의할 것이 하나 있다. 공용 설정은 계정 격리로 막히지 않는다. 환율, 수수료율, 기능 플래그처럼 전역에 하나뿐인 값을 테스트가 바꾸면 같은 환경의 모든 사람이 영향을 받는다. 전역 설정을 바꾸는 테스트는 언제 누가 하는지 미리 공유하거나 환경을 따로 쓴다.
시간에 따라 썩는 데이터
테스트 데이터에서 가장 자주 발목을 잡는 축이 시간이다. 어제까지 멀쩡했던 데이터가 오늘 못 쓰게 된다.
| 데이터 | 언제 썩나 |
|---|---|
| 쿠폰·프로모션 | 유효기간이 지난다 |
| 구독·멤버십 | 갱신일이 지나 해지 상태가 된다 |
| 인증 토큰·세션 | 만료된다 |
| 재고·한도 | 반복 테스트로 소진된다 |
| "최근 7일" 조건 데이터 | 날짜가 밀려 조건에서 빠진다 |
대응은 두 가지다.
- 고정 날짜를 쓰지 않는다 — "2026-12-31" 대신 "오늘 + 30일" 처럼 상대 날짜로 생성한다
- 시간을 주입할 수 있게 만든다 — 시스템 시각을 바꿔 테스트할 수 있으면 "만료 하루 전·하루 후" 를 즉시 만들 수 있다
두 번째는 개발과 함께 해야 하는 일이고, 요청할 만한 가치가 있다. 그것이 없으면 "만료 직후 동작" 을 확인할 방법이 사실상 없다.
외부 연동 데이터
결제·문자·지도처럼 외부 서비스가 끼면 데이터를 우리가 다 만들 수 없다.
| 상황 | 쓰는 것 |
|---|---|
| 결제 | 결제사가 공개한 테스트 카드번호와 샌드박스 키 |
| 문자·메일 | 테스트 수신 전용 주소·번호 |
| 외부 조회 | 모의 응답(모듈 13) 또는 샌드박스 |
여기서 절대 하지 않을 것이 있다. 실제 카드번호·실제 타인의 연락처를 테스트에 쓰는 것이다. 테스트 발송이 실제 사용자에게 가는 사고가 생각보다 자주 난다 — 운영 데이터를 복사해 쓰면서 메일 발송 기능을 켜 둔 것이 전형적인 경로다.
운영 데이터를 복제한 환경에서는 외부 발송을 반드시 차단한다. 이것은 데이터 관리가 아니라 환경 설정의 문제이고, 레슨 3에서 이어 받는다.
누가 관리하나
테스트 데이터는 주인이 없으면 반드시 썩는다. 정해 둘 것은 셋이다.
- 계정 세트 문서 — 어떤 계정이 어떤 상태인지 적힌 표. 비밀번호는 문서에 적지 않고 비밀 관리 도구에 둔다
- 생성 스크립트의 위치 — 코드 저장소에 둔다. 개인 PC에 있으면 사라진다
- 정리 주기 — 테스트가 만든 데이터를 언제 일괄 삭제할지
첫 줄이 없으면 매번 "VIP 계정 뭐였죠" 가 반복된다. 표 하나로 팀의 시간이 눈에 띄게 줄어드는, 비용 대비 효과가 가장 큰 문서다.
사례 — 실패 원인의 절반이 데이터였다
자동화를 도입한 팀의 기록이다. 야간에 돌리는 테스트 120건 중 매일 15~25건이 실패했는데, 코드 결함은 거의 없었다.
한 주간 실패 원인을 분류했다.
| 원인 | 건수 | 실제 내용 |
|---|---|---|
| 쿠폰 만료 | 41 | 고정 날짜 쿠폰이 기간을 지났다 |
| 계정 간섭 | 33 | 공용 테스트 계정을 두 테스트가 동시에 썼다 |
| 데이터 미정리 | 19 | 앞 테스트가 만든 주문이 목록 개수를 바꿨다 |
| 재고 소진 | 12 | 반복 주문으로 테스트 상품 재고가 0이 됐다 |
| 실제 코드 결함 | 7 | — |
실패 112건 중 7건만 결함이었다. 그 전까지 팀은 "자동화가 불안정하다" 고 결론 내리고 있었는데, 실제 문제는 데이터 관리의 부재였다.
고친 것은 네 가지다.
- 쿠폰·구독을 상대 날짜로 생성(오늘 + 30일)
- 테스트마다 계정을 새로 만들기로 전환
- 생성 데이터에 식별 접두사 부여 후 야간 일괄 정리
- 테스트 상품의 재고를 매일 시딩으로 복원
이후 실패가 하루 평균 2~3건으로 떨어졌고, 남은 실패는 대부분 진짜 결함이었다. "자동화를 고친 것이 아니라 데이터를 고쳤다."
실무에서 왜 필요한가
테스트 자동화(스테이지 4에서 본격적으로 다룬다)가 도입될수록 테스트 데이터 문제가 더 크게 드러난다 — 수동 테스트는 사람이 그때그때 데이터를 맞춰가며 진행할 수 있지만, 자동화된 테스트는 데이터가 항상 예측 가능한 상태여야 안정적으로 돈다. 테스트 데이터 관리가 부실하면 "자동화했더니 오히려 실패가 더 늘었다"는 흔한 실패 사례로 이어진다. 개인정보 마스킹 원칙을 모르고 운영 데이터를 그대로 테스트 환경에 복사하는 것은 실무에서 실제 보안 사고로 이어진 사례가 많은 지점이다.
불안정한 테스트의 원인을 가려낼 수 있게 된다
모듈 6 레슨 5에서 본 번갈아 통과·실패하는 케이스의 원인은 대개 둘 중 하나다 — 케이스가 애매하거나 데이터가 불안정한 것이다. 데이터 관리가 잡혀 있으면 후자가 제거되므로, 남은 실패를 코드 결함으로 신뢰할 수 있다.
이 신뢰가 없으면 더 나쁜 일이 생긴다. 사람들이 실패를 보고도 "또 데이터 문제겠지" 하고 넘기게 되고, 그 사이에 진짜 결함이 섞여 지나간다.
테스트 시간의 상당 부분이 데이터에 들어간다
수동 테스트에서 체감되는 비용이다. "결제 실패 이력이 있는 VIP 계정" 을 화면에서 만들려면 가입·등급 조정·주문·결제 실패를 차례로 해야 하고, 케이스 하나 실행보다 준비가 더 오래 걸린다.
계정 세트와 생성 스크립트가 있으면 그 시간이 거의 0이 된다. 탐색적 테스팅에서도 같은 효과가 있다 — 모듈 5 레슨 13의 차터 시간이 준비에 먹히지 않는다.
개인정보 사고는 QA 환경에서 자주 난다
보안 투자는 보통 운영 환경에 집중되고, 테스트 환경은 느슨하다. 그런데 운영 데이터를 복제해 두면 같은 가치의 데이터가 약한 울타리 안에 있게 된다. 공격자 입장에서는 더 쉬운 길이다.
QA가 할 수 있는 현실적인 방어는 둘이다 — 복제를 요청하지 않는 것, 그리고 복제가 불가피하면 마스킹과 외부 발송 차단을 조건으로 다는 것이다.
채용시장에서의 위치
테스트 데이터는 공고에 잘 안 적히고 실무에서 가장 많이 막히는 영역이다. 그래서 면접에서 물으면 실제로 해 본 사람과 안 해 본 사람이 바로 갈린다.
| 질문 | 약한 답 | 강한 답 |
|---|---|---|
| "테스트 데이터는 어떻게 준비하셨어요?" | "필요할 때 만들어서 썼습니다" | "계정 세트를 문서화하고 생성 스크립트를 저장소에 뒀습니다" |
| "운영 데이터를 쓸 수 있나요?" | "마스킹하면 됩니다" | "마스킹은 대개 가명처리 수준이라 개인정보로 관리해야 합니다. 조직 정책을 먼저 확인합니다" |
| "자동화가 자주 실패하면요?" | "원인을 봅니다" | "실패 원인을 분류합니다. 데이터·간섭·시간 만료가 결함보다 많은 경우가 흔합니다" |
| "테스트끼리 간섭하면?" | "순서를 조정합니다" | "테스트마다 계정을 새로 만들고, 생성 데이터에 식별 접두사를 붙입니다" |
| "날짜 관련 테스트는요?" | "데이터를 다시 만듭니다" | "고정 날짜 대신 상대 날짜로 생성하고, 시간 주입을 요청합니다" |
세 번째가 가장 변별력이 크다. "자동화가 불안정하다" 를 원인 분류로 바꿔 본 경험은 흔하지 않고, 그 경험이 있으면 자동화 도입 실패의 전형적인 함정을 피할 수 있는 사람으로 읽힌다.
두 번째는 보안 감각을 보는 질문이다. "마스킹하면 된다" 로 끝내는 답과, 가명처리의 법적 의미까지 아는 답의 차이가 크다. 금융·의료·공공 도메인에서는 특히 그렇다.
공고 표현으로는 "테스트 데이터 관리", "테스트 환경 구성", "개인정보 처리 경험" 이 이 레슨에 걸린다. 자동화 쪽으로 가려면 사실상 필수이고, 모듈 13 레슨 10에서 코드로 구현하는 모습을 본다.