브라우저 컨텍스트와 테스트 격리

브라우저 컨텍스트와 테스트 격리

Playwright로 작성한 테스트는 "브라우저 컨텍스트"라고 부르는 깨끗한 격리 환경 안에서 실행돼요. 이 격리 모델 덕분에 재현성이 좋아지고, 한 테스트의 실패가 다른 테스트로 번지지 않아요. 왜 격리가 중요한지, 그리고 Playwright가 어떻게 컨텍스트로 그것을 이루는지 차근차근 보여 드릴게요.

출처: Playwright 공식 문서 — Isolation (Browser Contexts)

본문

테스트 격리란 무엇일까요

테스트 격리란 각 테스트가 다른 테스트와 완전히 분리되는 것을 말해요. 모든 테스트는 서로 독립적으로 실행되죠. 즉 각 테스트마다 자신만의 로컬 스토리지, 세션 스토리지, 쿠키를 갖게 돼요. Playwright는 시크릿 모드 프로필처럼 동작하는 [BrowserContext]로 이를 구현해요. 컨텍스트는 만들기가 빠르고 비용이 낮으며, 하나의 브라우저 안에서 실행해도 완전히 격리돼요. 테스트마다 컨텍스트가 생성되고, 그 안에 기본 [Page]가 하나 제공됩니다.

테스트 격리가 왜 중요한가요

  • 실패가 넘어가지 않아요. 한 테스트가 실패해도 다른 테스트에는 영향이 없어요.
  • 디버깅이 쉬워요. 실패나 불안정함을 조사할 때 단일 테스트만 원하는 만큼 다시 돌릴 수 있으니까요.
  • 순서를 고민하지 않아도 돼요. 병렬 실행, 샤딩(sharding) 등에서 순서를 신경 쓸 필요가 없어요.

격리의 두 가지 방식

테스트 격리 전략에는 "시작부터 새로"와 "사이 정리"라는 두 가지가 있어요. 테스트 사이를 정리하는 방식은, 정리를 깜빡하기 쉽고 "방문한 링크"처럼 정리할 수 없는 것들도 있다는 게 문제예요. 한 테스트의 상태가 다음 테스트로 새면 실패 원인이 다른 테스트에서 나와 디버깅이 훨씬 어려워지죠. 반대로 시작부터 새로 만들면 모든 게 새 상태라서, 실패가 나면 그 테스트 안에서만 원인을 찾으면 됩니다.

Playwright가 격리를 이루는 법

Playwright는 테스트 격리를 위해 브라우저 컨텍스트를 사용해요. 각 테스트는 자신만의 Browser Context를 갖고, 테스트를 실행할 때마다 새 컨텍스트가 만들어져요. Playwright를 테스트 러너로 쓰면 컨텍스트가 기본으로 생성되고, 그 외에는 수동으로 만들면 돼요.

import { test } from '@playwright/test';

test('example test', async ({ page, context }) => {
  // "context" is an isolated BrowserContext, created for this specific test.
  // "page" belongs to this context.
});

test('another test', async ({ page, context }) => {
  // "context" and "page" in this second test are completely
  // isolated from the first test.
});
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();

브라우저 컨텍스트는 모바일 기기, 권한, 로케일, 색상 스킴 같은 다중 페이지 시나리오를 에뮬레이션하는 데도 쓸 수 있어요. 자세한 내용은 에뮬레이션 가이드를 참고하세요.

하나의 테스트에서 여러 컨텍스트 만들기

한 시나리오 안에서 브라우저 컨텍스트를 여러 개 만들 수도 있어요. 채팅처럼 다중 사용자 기능을 테스트할 때 유용하죠.

import { test } from '@playwright/test';

test('admin and user', async ({ browser }) => {
  // Create two isolated browser contexts
  const adminContext = await browser.newContext();
  const userContext = await browser.newContext();

  // Create pages and interact with contexts independently
  const adminPage = await adminContext.newPage();
  const userPage = await userContext.newPage();
});

더 알아보기