E2E(End-to-End) 테스트는 실제 브라우저에서 사용자의 행동을 시뮬레이션하여 애플리케이션 전체가 올바르게 동작하는지 검증합니다.

면접에서 "단위 테스트와 E2E 테스트의 차이"를 물어보면, 테스트 피라미드 에서의 역할과 비용을 설명할 수 있어야 합니다.


테스트 피라미드

PLAINTEXT
          ┌─────────┐
          │   E2E   │  ← 적게, 핵심 시나리오만
         ─┼─────────┼─
        │  통합 테스트  │
       ─┼─────────────┼─
      │    단위 테스트    │  ← 많이, 빠르게
     ─┴─────────────────┴─

E2E: 느리고 비용이 높지만, 실제 사용자 경험을 검증
단위: 빠르고 비용이 낮지만, 통합 동작을 보장하지 않음

Playwright 설정

TYPESCRIPT
// playwright.config.ts
import { defineConfig } from '@playwright/test'

export default defineConfig({
  testDir: './e2e',
  timeout: 30000,
  use: {
    baseURL: 'http://localhost:5173',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure'
  },
  webServer: {
    command: 'npm run dev',
    port: 5173,
    reuseExistingServer: !process.env.CI
  }
})

Playwright 테스트 작성

TYPESCRIPT
// e2e/login.spec.ts
import { test, expect } from '@playwright/test'

test.describe('로그인 플로우', () => {
  test('유효한 자격 증명으로 로그인 성공', async ({ page }) => {
    await page.goto('/login')

    // 폼 입력
    await page.fill('[data-testid="email"]', 'test@example.com')
    await page.fill('[data-testid="password"]', 'password123')
    await page.click('[data-testid="submit"]')

    // 대시보드로 리다이렉트 확인
    await expect(page).toHaveURL('/dashboard')
    await expect(page.locator('[data-testid="welcome"]')).toContainText('안녕하세요')
  })

  test('잘못된 비밀번호로 에러 메시지 표시', async ({ page }) => {
    await page.goto('/login')

    await page.fill('[data-testid="email"]', 'test@example.com')
    await page.fill('[data-testid="password"]', 'wrong')
    await page.click('[data-testid="submit"]')

    await expect(page.locator('[data-testid="error"]')).toBeVisible()
    await expect(page.locator('[data-testid="error"]')).toContainText('비밀번호가 올바르지 않습니다')
  })
})

Cypress 테스트 작성

TYPESCRIPT
// cypress/e2e/todo.cy.ts
describe('Todo 앱', () => {
  beforeEach(() => {
    cy.visit('/')
  })

  it('새 할일을 추가할 수 있다', () => {
    cy.get('[data-testid="new-todo"]').type('Vue 공부하기{enter}')

    cy.get('[data-testid="todo-list"]')
      .should('contain', 'Vue 공부하기')
  })

  it('할일을 완료 처리할 수 있다', () => {
    cy.get('[data-testid="new-todo"]').type('테스트 작성{enter}')
    cy.get('[data-testid="todo-checkbox"]').first().click()

    cy.get('[data-testid="todo-item"]').first()
      .should('have.class', 'completed')
  })

  it('완료된 할일을 삭제할 수 있다', () => {
    cy.get('[data-testid="new-todo"]').type('삭제할 항목{enter}')
    cy.get('[data-testid="delete-btn"]').first().click()

    cy.get('[data-testid="todo-list"]')
      .should('not.contain', '삭제할 항목')
  })
})

Page Object Model 패턴

TYPESCRIPT
// e2e/pages/LoginPage.ts
import { type Page, type Locator } from '@playwright/test'

export class LoginPage {
  readonly page: Page
  readonly emailInput: Locator
  readonly passwordInput: Locator
  readonly submitButton: Locator
  readonly errorMessage: Locator

  constructor(page: Page) {
    this.page = page
    this.emailInput = page.locator('[data-testid="email"]')
    this.passwordInput = page.locator('[data-testid="password"]')
    this.submitButton = page.locator('[data-testid="submit"]')
    this.errorMessage = page.locator('[data-testid="error"]')
  }

  async goto() {
    await this.page.goto('/login')
  }

  async login(email: string, password: string) {
    await this.emailInput.fill(email)
    await this.passwordInput.fill(password)
    await this.submitButton.click()
  }
}
TYPESCRIPT
// e2e/login.spec.ts
import { test, expect } from '@playwright/test'
import { LoginPage } from './pages/LoginPage'

test('로그인 성공', async ({ page }) => {
  const loginPage = new LoginPage(page)
  await loginPage.goto()
  await loginPage.login('test@example.com', 'password123')

  await expect(page).toHaveURL('/dashboard')
})

어떤 것을 E2E로 테스트해야 하나?

PLAINTEXT
E2E 테스트 대상:
✓ 핵심 사용자 플로우 (로그인, 결제, 가입)
✓ 여러 페이지에 걸친 시나리오
✓ 브라우저 특유 동작 (쿠키, 로컬스토리지)

단위/컴포넌트 테스트 대상:
✓ 개별 컴포넌트 동작
✓ Composable 로직
✓ 유틸리티 함수
✓ 에지 케이스

면접 팁

  • E2E 테스트는 비용이 높으므로 핵심 시나리오만 작성하는 것이 원칙입니다
  • Playwright vs Cypress 선택 기준: Playwright는 다중 브라우저 지원과 병렬 실행이 강점, Cypress는 개발자 경험과 디버깅이 강점
  • Page Object Model 패턴 을 사용하면 테스트 유지보수성이 크게 향상됩니다

요약

E2E 테스트는 실제 브라우저에서 사용자 시나리오를 검증합니다. Playwright이나 Cypress를 활용하며, 핵심 플로우만 테스트하고 나머지는 단위/컴포넌트 테스트로 커버합니다. Page Object Model 패턴으로 테스트 코드의 유지보수성을 높이세요.

댓글 로딩 중...