본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 15. 15:18

실제로 의미 있는 QA 실험: 브라우저 자동화, AI 에이전트, 그리고 CI의 현실

요약

실제 제품 개발 환경에서 발생하는 브라우저 자동화 및 CI 테스트의 복잡성과 한계를 다룹니다. 단순한 테스트 개수보다 테스트의 신뢰성과 조치 가능한 관측 가능성(observability)을 확보하는 것이 중요함을 강조합니다.

핵심 포인트

  • 테스트 개수보다 실패의 신뢰성과 조치 가능성이 더 중요함
  • Flaky test, 재시도 비율 등 실질적인 지표 관리가 필요함
  • CI 환경과 로컬 환경의 차이로 인한 실패 패턴을 이해해야 함
  • 스크린샷, 트레이스 등 디버깅을 위한 관측 가능성 확보가 필수적임

대부분의 테스트 조언은 실제 테스트 작업보다 더 깔끔하게 들립니다.

깔끔한 버전에서는 도구를 선택하고, 몇 가지 테스트를 작성한 뒤, 이를 CI에 추가하여 매 릴리스 전에 깔끔한 초록색 또는 빨간색 답변을 얻습니다.

실제 버전에서는 브라우저 스위트(browser suite)가 모킹된 API(mocked APIs)에 의존하고, 프론트엔드 변경으로 인해 셀렉터(selectors)가 깨지며, CI에서 React 하이드레이션(hydration)이 다르게 동작하고, 피처 플래그(feature flag)가 바뀌며, AI가 생성한 테스트가 그럴싸해 보이지만 잘못된 것을 단언(assert)하고, Playwright 작업이 로컬에서는 통과하지만 GitHub Actions 병렬 처리 환경에서는 실패합니다.

이것이 제가 실험실 스타일의 QA 글쓰기를 좋아하는 이유입니다. 이는 하나의 완벽한 도구를 선언하는 것이라기보다 다음과 같이 질문하는 것에 가깝습니다.

실제로 무엇이 깨졌는가, 우리는 무엇을 측정했는가, 그리고 다음에는 무엇을 바꿀 것인가?

저는 Vibium Labs의 현재 실험 노트들을 살펴보고, QA 팀, SDET, 프론트엔드 엔지니어, 그리고 실제 제품 개발 과정에서도 살아남는 테스트 자동화를 구축하려는 창업자들을 위해 실용적인 읽기 경로로 그룹화했습니다.

테스트 개수가 아닌 관측 가능성(observability)부터 시작하세요

많은 팀이 여전히 자동화의 척도를 테스트 개수로 측정합니다.

이해할 수 있는 일이지만, 그 자체로는 그리 유용하지 않습니다.

2,000개의 테스트가 있는 스위트라도 아무도 실패를 신뢰하지 않는다면 여전히 약한 릴리스 신호를 생성할 수 있습니다. 반면, 의미 있는 회귀(regressions)를 잡아내고, 좋은 실패 증거를 생성하며, UI 변경 후에도 유지보수가 가능한 더 작은 스위트가 더 가치 있을 수 있습니다.

이것이 다음 두 노트가 좋은 시작점이 되는 이유입니다:

유용한 지표는 통과율(pass rate)과 실행 시간(runtime)만이 아닙니다.

여러분은 다음을 이해해야 합니다:

  • 불안정한 테스트 비율 (flaky test rate)
  • 재시도 비율 (retry rate)
  • 실패 디버깅 평균 시간 (mean time to debug failures)
  • 실패 분류 정확도 (failure classification accuracy)
  • 로케이터 상태 (locator health)
  • 환경 드리프트 (environment drift)
  • CI 전용 실패 패턴 (CI-only failure patterns)
  • 테스트 데이터 최신성 (test data freshness)
  • 얼마나 많은 실패가 조치 가능한가 (how many failures are actionable)

마지막 단어가 중요합니다: 조치 가능성 (actionable).

실패는 팀이 무엇이 일어났는지, 그리고 다음에 무엇을 해야 하는지 알 수 있을 때만 유용합니다.

스크린샷 (Screenshots), 트레이스 (traces), 콘솔 로그 (console logs), 네트워크 로그 (network logs), DOM 스냅샷 (DOM snapshots), 브라우저 버전 (browser versions), 피스처 버전 (fixture versions), 그리고 환경 메타데이터 (environment metadata)는 있으면 좋은 부가 기능이 아닙니다. 이것들은 실패한 빌드를 디버깅 가능한 신호로 바꿔주는 핵심 요소입니다.

관측 가능성 (observability) 없이는 테스트 자동화는 추측 게임이 되어버립니다.

모킹된 API는 브라우저 테스트 스위트를 실제보다 더 건강해 보이게 만들 수 있습니다

API를 모킹 (Mocking)하는 것은 유용합니다.

브라우저 테스트를 더 빠르고, 결정론적 (deterministic)이며, 백엔드 가용성에 덜 의존하게 만들 수 있습니다. 많은 프론트엔드 팀에게 모킹된 API 테스트는 불안정한 다운스트림 시스템을 기다리지 않고 UI 동작을 커버할 수 있는 좋은 방법입니다.

하지만 모킹은 위험을 숨기기도 합니다.

이 노트는 문제를 잘 설명하고 있습니다:

위험은 결정론적 (determinism)인 상태를 신뢰도 (confidence)와 혼동하는 데 있습니다.

모킹된 API 테스트는 UI가 통제된 버전의 세상에서 작동하기 때문에 통과할 수 있습니다. 하지만 프로덕션은 통제되지 않습니다. 백엔드 계약 (Backend contracts)은 변경됩니다. 에러 응답은 다양합니다. 지연 시간 (Latency)이 발생합니다. 페이지네이션 (Pagination)은 다르게 동작합니다. 인증 (Auth)은 만료됩니다. 모킹이 전혀 표현하지 못한 실제 데이터에서 엣지 케이스 (Edge cases)가 나타납니다.

즉, 모킹된 브라우저 테스트 스위트에는 자체적인 측정 지표가 필요합니다:

  • 계약 드리프트 비율 (contract drift rate)
  • 모킹 최신성 (mock freshness)
  • 모킹된 응답과 실제 응답 간의 불일치 비율 (mismatch rate between mocked and real responses)
  • 엣지 케이스 커버리지 (edge-case coverage)
  • 실제 통합 탈출률 (real integration escape rate)
  • 백엔드 변경 후 모킹이 업데이트되는 빈도 (how often mocks are updated after backend changes)

모킹이 너무 오래되었거나, 너무 해피 패스 (happy-path) 위주이거나, 실제 트래픽과 너무 동떨어져 있다면, 통합 위험은 증가하는 동안 브라우저 테스트 스위트는 계속 통과할 수 있습니다.

해결책은 모킹 사용을 중단하는 것이 아닙니다.

해결책은 모킹 (Mocking)을 테스트 자산 (Test assets)으로 취급하여, 시간이 지남에 따라 노후화된다는 점을 인정하는 것입니다. 모킹에는 소유권, 텔레메트리 (Telemetry), 그리고 실제 동작과의 정기적인 비교가 필요합니다.

계약 테스트 (Contract tests)는 프론트엔드의 확신과 백엔드의 현실 사이를 잇는 가교입니다

모킹된 브라우저 테스트가 프론트엔드와 백엔드 간의 괴리 (Drift)를 숨길 수 있다면, 계약 테스트 (Contract tests)는 그 괴리를 더 일찍 포착할 수 있는 한 가지 방법입니다.

다음 노트가 도움이 될 것입니다:

아이디어는 간단합니다. API 형태 (Shape)가 변경되었다는 것을 발견하기 위해 브라우저 회귀 테스트 (Regression test)를 기다리지 마십시오.

브라우저 테스트는 계약 문제를 디버깅하기에 비용이 많이 드는 환경입니다. UI 테스트가 실패할 때쯤이면, 여러분은 셀렉터 타임아웃 (Selector timeout), 누락된 요소 (Missing element), 이상한 어설션 실패 (Assertion failure), 또는 깨진 페이지 상태 (Broken page state)를 보고 있을지도 모릅니다. 실제 원인은 두 단계 아래에서 변경된 API 필드일 수 있습니다.

계약 테스트는 이러한 불일치를 더 빠르고 직접적으로 포착할 수 있습니다.

프론트엔드 팀이 피스처 (Fixtures), 모킹 (Mocks), 생성된 클라이언트 (Generated clients), 또는 백엔드 응답에 대한 가정에 크게 의존할 때 특히 유용합니다.

목표는 브라우저 테스트를 대체하는 것이 아닙니다. 브라우저 테스트가 모든 통합 불일치를 진단하도록 강요하는 대신, 사용자 행동에 집중할 수 있도록 유지하는 것입니다.

CI 실패는 시스템 문제입니다

CI 실패는 종종 테스트 실패와 동일하게 취급됩니다.

하지만 그것이 항상 사실인 것은 아닙니다.

브라우저 작업 (Browser job)이 CI에서 실패하는 이유는 제품이 고장 났기 때문일 수도 있지만, 환경이 더 느려졌거나, 테스트가 병렬로 실행되거나, 공유 상태 (Shared state)가 유출되었거나, 피스처 (Fixture)가 충돌했거나, 브라우저 버전이 변경되었거나, 또는 리소스 제한 (Resource limit)에 도달했기 때문일 수도 있습니다.

다음 가이드는 매우 실용적입니다:

병렬성 (Parallelism)은 숨겨진 가정들이 드러나는 지점입니다.

로컬에서 작동하는 테스트 스위트가 다음과 같은 상황에서 실패할 수 있습니다:

  • 두 테스트가 동일한 계정을 사용함
  • 테스트 데이터가 격리되지 않음
  • 스토리지 상태 (storage state)가 유출됨
  • 포트 (ports) 충돌
  • 워커 (workers) 간의 CPU 경쟁
  • 실행 순서에 대한 가정이 사라짐
  • 재시도 (retries)가 원래의 실패를 숨김
  • 환경이 로컬 실행보다 느려짐

그렇기 때문에 CI 디버깅에는 구조가 필요합니다.

실패의 원인이 다음 중 무엇인지 알아야 합니다:

  • 제품 동작 (product behavior)
  • 테스트 로직 (test logic)
  • 테스트 데이터 (test data)
  • 셀렉터 불안정성 (selector instability)
  • 환경 드리프트 (environment drift)
  • 타이밍 (timing)
  • 자원 경합 (resource contention)
  • 병렬 실행 (parallel execution)

실패를 이런 방식으로 분류하기 전까지는, 모든 빌드 실패(red build)가 마치 풀 수 없는 미스터리처럼 느껴질 것입니다.

그리고 미스터리한 문제들은 확장성(scale)을 가질 수 없습니다.

Playwright의 불안정성 (flakiness)에는 대개 특징이 있습니다

Playwright는 강력한 도구이지만, 브라우저의 불안정성 (flakiness)을 마법처럼 제거해주지는 않습니다.

이 가이드는 실패의 특징 (failure signatures)에 집중하기 때문에 유용합니다:

불안정한 테스트 (Flaky tests)에는 대개 패턴이 있습니다.

타이밍 실패는 셀렉터 드리프트 (selector drift)와 다르게 보입니다. 환경 드리프트 (environment drift)는 잘못된 테스트 데이터와 다르게 보입니다. 레이스 컨디션 (Race conditions)은 실제 제품의 회귀 (regression)와 다르게 보입니다. 실패에 적절한 라벨을 붙이기 시작하면, 해결 방법은 더 명확해집니다.

예를 들어:

  • 요소가 존재하지만 준비되지 않았다면, 문제는 대기 로직 (wait logic)일 수 있습니다.
  • 잘못된 요소가 클릭된다면, 문제는 셀렉터 모호성 (selector ambiguity)일 수 있습니다.
  • 테스트가 CI에서만 실패한다면, 문제는 타이밍, 자원, 또는 환경일 수 있습니다.
  • 실패가 특정 계정이나 픽스처 (fixture)를 따라 발생한다면, 문제는 데이터 상태 (data state)일 수 있습니다.
  • CSS 변경 후 실패가 집중된다면, 문제는 레이아웃 시프트 (layout shift) 또는 셀렉터 결합 (selector coupling)일 수 있습니다.

중요한 습관은 “테스트가 불안정하다 (flaky)”라고 말하는 것을 멈추고, ‘왜’ 그런지 말하기 시작하는 것입니다.

불안정성 (Flakiness)은 증상일 뿐입니다. 해결 방법은 실패의 유형 (failure class)에 달려 있습니다.

작은 CSS 변경이 스크린샷보다 더 많은 것을 망가뜨릴 수 있습니다

프론트엔드 팀은 때때로 작은 CSS 변경이 자동화에 얼마나 큰 영향을 미칠 수 있는지 과소평가하곤 합니다.

클래스 변경, 간격 조정, 애니메이션, 레이아웃 이동 (layout shift), 반응형 중단점 (responsive breakpoint), 또는 숨겨진 오버플로 (overflow) 변경은 기능적 동작이 여전히 정상임에도 불구하고 테스트를 실패하게 만들 수 있습니다.

이 가이드가 해당 내용을 잘 다루고 있습니다:

CSS 변경은 다음과 같은 여러 방식으로 테스트를 망가뜨릴 수 있습니다:

  • 클릭 대상 (click target)이 이동함
  • 요소가 다른 것에 의해 가려짐
  • 로케이터 (locator)가 다른 노드와 일치함
  • 스크린샷 차이 (screenshot diff)에 노이즈가 발생함
  • 애니메이션이 상호작용을 지연시킴
  • 반응형 레이아웃이 DOM 순서를 변경함
  • 포커스 (focus) 동작이 변경됨
  • 숨겨진 콘텐츠가 보이게 되거나 그 반대의 경우가 발생함

이것이 바로 프론트엔드 테스트가 가능할 때마다 의미론적 로케이터 (semantic locators)와 사용자에게 보이는 의도 (user-visible intent)를 우선시해야 하는 이유입니다.

DOM 구조나 스타일링 세부 사항에 너무 밀접하게 결합된 테스트는 시간이 지날수록 상태가 나빠질 것입니다.

좋은 브라우저 테스트는 래퍼 (wrapper) 내부의 세 번째 div가 여전히 동일한 클래스를 가지고 있는지 여부가 아니라, 사용자가 흐름 (flow)을 완료할 수 있는지에 집중해야 합니다.

브라우저 호환성은 여전히 릴리스 리스크입니다

브라우저 호환성 테스트는 Safari에서만 나타나거나 모바일에서만 발생하는 버그를 발견하기 전까지는 구식처럼 느껴질 수 있습니다.

이 체크리스트는 유용한 릴리스 동반자 역할을 합니다:

현대적인 브라우저 호환성 문제는 단순히 "Chrome, Firefox, Safari, Edge에서 작동하는가?"에 그치지 않습니다.

다음 사항들도 포함됩니다:

  • 렌더링 엔진 (rendering engine) 차이
  • 데스크톱 대 모바일 동작
  • 뷰포트 (viewport) 특정 레이아웃 변경
  • 입력 처리 (input handling)
  • 쿠키 및 스토리지 (storage) 동작
  • 파일 업로드 및 다운로드 동작
  • 접근성 (accessibility) 설정
  • 자동 완성 (autofill)
  • 미디어 권한 (media permissions)
  • 기업용 브라우저 정책 (enterprise browser policies)
  • OS 레벨의 차이

목표는 모든 테스트를 모든 곳에서 실행하는 것이 아닙니다.

목표는 어떤 흐름(flow)이 교차 브라우저 (cross-browser) 커버리지를 가질 가치가 있는지를 식별하는 것입니다. 일반적으로 이는 핵심 비즈니스 흐름, 레이아웃에 민감한 화면, 양식 (forms), 계정 흐름, 결제 (checkout), 대시보드, 그리고 최근 프론트엔드 변경의 영향을 받은 모든 것을 의미합니다.

Shadow DOM, iframe, 그리고 중첩된 위젯은 취약한 셀렉터 전략을 드러냅니다

단순한 페이지는 브라우저 자동화의 좋은 벤치마크가 아닙니다.

도구 선택과 테스트 설계가 중요해지기 시작하는 지점은 더 어려운 케이스들입니다:

  • Shadow DOM
  • iframe
  • 임베디드 위젯 (embedded widgets)
  • 제3자 결제 (third-party checkout)
  • 리치 에디터 (rich editors)
  • 중첩된 컴포넌트 (nested components)
  • 교차 출처 경계 (cross-origin boundaries)

이 노트가 도움이 될 것입니다:

핵심 교훈은 오늘 테스트를 통과하게 만들지만 내일은 유지보수가 불가능해지는 셀렉터 해킹 (selector hacks)을 피하는 것입니다.

Shadow DOM과 iframe은 테스트가 컨텍스트 (context)에 대해 명시적일 것을 요구합니다. 테스트는 요소가 어디에 존재하는지, 어떤 경계를 넘는지, 그리고 어떤 사용자 동작을 검증하고 있는지를 알아야 합니다.

나쁜 테스트는 중첩된 위젯을 마치 DOM 보물찾기처럼 취급합니다.

좋은 테스트는 나중에 누군가가 디버깅할 수 있을 정도로 상호작용을 명확하게 모델링합니다.

React 하이드레이션 (hydration) 문제는 브라우저의 불안정성 (flakiness)처럼 보일 수 있습니다

React SSR과 하이드레이션 (hydration)은 특정한 종류의 테스트 문제를 생성합니다.

페이지는 서버에서 렌더링된 HTML을 포함할 수 있으며, 그 후 React가 이를 하이드레이션하고, 이벤트 핸들러를 부착하며, DOM을 조정(reconcile)하고, 때로는 브라우저가 보는 내용을 변경합니다.

이 프로세스가 불안정할 때, 브라우저 테스트는 혼란스러운 방식으로 실패할 수 있습니다.

다음 두 가지 노트는 함께 활용하면 유용합니다:

Hydration 관련 테스트는 실제 렌더링 결함과 노이즈를 분리해야 합니다.

일반적인 원인은 다음과 같습니다:

  • UI가 안정화되기 전에 실행되는 테스트
  • 서버와 클라이언트의 렌더링 값이 서로 다름
  • 무작위 ID (Random IDs)
  • 시간 및 시간대(Timezone) 차이
  • 로캘(Locale) 포맷팅
  • 뷰포트(Viewport)에 의존적인 렌더링
  • 피처 플래그 (Feature flags)
  • 제3자 스크립트 (Third-party scripts)
  • 불안정한 셀렉터 (Unstable selectors)

Hydration 경고가 항상 사용자에게 보이는 버그인 것은 아니지만, 유용한 신호가 됩니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0