Skip to content

Bun 의 테스트 러너는 이제 내장 코드 커버리지 리포팅을 지원합니다. 이를 통해 코드베이스의 얼마나 많은 부분이 테스트로 커버되는지 쉽게 확인하고 현재 충분히 테스트되지 않은 영역을 찾을 수 있습니다.

커버리지 활성화

bun:test 는 어떤 코드 줄이 테스트로 커버되는지 확인할 수 있습니다. 이 기능을 사용하려면 CLI 에 --coverage 를 전달하세요. 콘솔에 커버리지 리포트를 출력합니다.

bash
bun test --coverage

-------------|---------|---------|-------------------
File         | % Funcs | % Lines | Uncovered Line #s
-------------|---------|---------|-------------------
All files    |   38.89 |   42.11 |
 index-0.ts  |   33.33 |   36.84 | 10-15,19-24
 index-1.ts  |   33.33 |   36.84 | 10-15,19-24
 index-10.ts |   33.33 |   36.84 | 10-15,19-24
 index-2.ts  |   33.33 |   36.84 | 10-15,19-24
 index-3.ts  |   33.33 |   36.84 | 10-15,19-24
 index-4.ts  |   33.33 |   36.84 | 10-15,19-24
 index-5.ts  |   33.33 |   36.84 | 10-15,19-24
 index-6.ts  |   33.33 |   36.84 | 10-15,19-24
 index-7.ts  |   33.33 |   36.84 | 10-15,19-24
 index-8.ts  |   33.33 |   36.84 | 10-15,19-24
 index-9.ts  |   33.33 |   36.84 | 10-15,19-24
 index.ts    |  100.00 |  100.00 |
-------------|---------|---------|-------------------

기본적으로 활성화

기본적으로 항상 커버리지 리포팅을 활성화하려면 bunfig.toml 에 다음 줄을 추가하세요.

toml
[test]
# 항상 커버리지 활성화
coverage = true

기본적으로 커버리지 리포트는 테스트 파일을 포함하고 소스맵을 제외합니다. 이것이 일반적으로 원하는 것이지만 bunfig.toml 에서 다르게 구성할 수 있습니다.

toml
[test]
coverageSkipTestFiles = true  # 기본값 false

커버리지 임계값

bunfig.toml 에 커버리지 임계값을 지정할 수 있습니다. 테스트 스위트가 이 임계값을 충족하거나 초과하지 못하면 bun test 는 실패를 나타내기 위해 0 이 아닌 종료 코드로 종료됩니다.

간단한 임계값

toml
[test]
# 90% 줄 단위 및 함수 단위 커버리지가 필요한 경우
coverageThreshold = 0.9

상세 임계값

toml
[test]
# 줄과 함수에 대해 다른 임계값 설정
coverageThreshold = { lines = 0.9, functions = 0.9, statements = 0.9 }

이러한 임계값 중 하나를 설정하면 fail_on_low_coverage 가 활성화되어 커버리지가 임계값 미만일 경우 테스트 실행이 실패합니다.

커버리지 리포터

기본적으로 커버리지 리포트는 콘솔에 출력됩니다.

CI 환경 및 기타 도구의 지속적인 코드 커버리지 리포트를 위해 --coverage-reporter=lcov CLI 옵션이나 bunfig.tomlcoverageReporter 옵션을 전달할 수 있습니다.

toml
[test]
coverageReporter = ["text", "lcov"]  # 기본값 ["text"]
coverageDir = "path/to/somewhere"    # 기본값 "coverage"

사용 가능한 리포터

리포터설명
text콘솔에 커버리지의 텍스트 요약을 출력합니다
lcovlcov 형식으로 커버리지를 저장합니다

LCOV 커버리지 리포터

lcov 리포트를 생성하려면 lcov 리포터를 사용할 수 있습니다. 이는 커버리지 디렉토리에 lcov.info 파일을 생성합니다.

toml
[test]
coverageReporter = "lcov"
bash
# 또는 CLI 를 통해
bun test --coverage --coverage-reporter=lcov

LCOV 형식은 다양한 도구 및 서비스에서 널리 지원됩니다.

  • 코드 에디터: VS Code 확장 프로그램은 인라인으로 커버리지를 표시할 수 있습니다
  • CI/CD 서비스: GitHub Actions, GitLab CI, CircleCI
  • 커버리지 서비스: Codecov, Coveralls
  • IDE: WebStorm, IntelliJ IDEA

GitHub Actions 에서 LCOV 사용

yaml
name: Test with Coverage
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      - run: bun test --coverage --coverage-reporter=lcov
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/lcov.info

커버리지에서 파일 제외

테스트 파일 건너뛰기

기본적으로 테스트 파일 자체는 커버리지 리포트에 포함됩니다. 다음을 사용하여 제외할 수 있습니다.

toml
[test]
coverageSkipTestFiles = true  # 기본값 false

이렇게 하면 테스트 패턴 (예: *.test.ts, *.spec.js) 과 일치하는 파일이 커버리지 리포트에서 제외됩니다.

특정 경로 및 패턴 무시

coveragePathIgnorePatterns 를 사용하여 특정 파일이나 파일 패턴을 커버리지 리포트에서 제외할 수 있습니다.

toml
[test]
# 단일 패턴
coveragePathIgnorePatterns = "**/*.spec.ts"

# 여러 패턴
coveragePathIgnorePatterns = [
  "**/*.spec.ts",
  "**/*.test.ts",
  "src/utils/**",
  "*.config.js"
]

이 옵션은 glob 패턴을 허용하며 Jest 의 collectCoverageFrom 무시 패턴과 유사하게 작동합니다. 이러한 패턴 중 하나와 일치하는 파일은 텍스트 및 LCOV 출력 모두에서 커버리지 계산 및 리포팅에서 제외됩니다.

일반적인 사용 사례

toml
[test]
coveragePathIgnorePatterns = [
  # 유틸리티 파일 제외
  "src/utils/**",

  # 구성 파일 제외
  "*.config.js",
  "webpack.config.ts",
  "vite.config.ts",

  # 특정 테스트 패턴 제외
  "**/*.spec.ts",
  "**/*.e2e.ts",

  # 빌드 산출물 제외
  "dist/**",
  "build/**",

  # 생성된 파일 제외
  "src/generated/**",
  "**/*.generated.ts",

  # 벤더/서드파티 코드 제외
  "vendor/**",
  "third-party/**"
]

소스맵

내부적으로 Bun 은 기본적으로 모든 파일을 트랜스파일하므로 Bun 은 원래 소스 코드의 줄을 Bun 의 내부 표현에 매핑하는 내부 소스 맵을 자동으로 생성합니다. 어떤 이유로든 이를 비활성화하려면 test.coverageIgnoreSourcemapstrue 로 설정하세요. 이는 고급 사용 사례 외에는 거의 바람직하지 않습니다.

toml
[test]
coverageIgnoreSourcemaps = true  # 기본값 false

커버리지 기본값

기본적으로 커버리지 리포트는 다음을 수행합니다.

  • 제외 node_modules 디렉토리
  • 제외 비 JS/TS 로더를 통해 로드된 파일 (예: .css, .txt). 단, 커스텀 JS 로더가 지정된 경우 제외
  • 포함 테스트 파일 자체 (coverageSkipTestFiles = true 로 비활성화 가능)
  • coveragePathIgnorePatterns 로 추가 파일 제외 가능

고급 구성

커스텀 커버리지 디렉토리

toml
[test]
coverageDir = "coverage-reports"  # 기본값 "coverage"

여러 리포터

toml
[test]
coverageReporter = ["text", "lcov"]

특정 테스트 패턴과 함께 커버리지

bash
# 특정 테스트 파일에서만 커버리지 실행
bun test --coverage src/components/*.test.ts

# 이름 패턴으로 커버리지 실행
bun test --coverage --test-name-pattern="API"

CI/CD 통합

GitHub Actions 예시

yaml
name: Coverage Report
on: [push, pull_request]

jobs:
  coverage:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Bun
        uses: oven-sh/setup-bun@v2

      - name: Install dependencies
        run: bun install

      - name: Run tests with coverage
        run: bun test --coverage --coverage-reporter=lcov

      - name: Upload to Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/lcov.info
          fail_ci_if_error: true

GitLab CI 예시

yaml
test:coverage:
  stage: test
  script:
    - bun install
    - bun test --coverage --coverage-reporter=lcov
  coverage: '/Lines\s*:\s*(\d+.\d+)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/lcov.info

커버리지 리포트 해석

텍스트 출력 설명

-------------|---------|---------|-------------------
File         | % Funcs | % Lines | Uncovered Line #s
-------------|---------|---------|-------------------
All files    |   85.71 |   90.48 |
 src/        |   85.71 |   90.48 |
  utils.ts   |  100.00 |  100.00 |
  api.ts     |   75.00 |   85.71 | 15-18,25
  main.ts    |   80.00 |   88.89 | 42,50-52
-------------|---------|---------|-------------------
  • % Funcs: 테스트 중에 호출된 함수의 백분율
  • % Lines: 테스트 중에 실행된 실행 가능한 줄의 백분율
  • Uncovered Line #s: 실행되지 않은 특정 줄 번호

목표해야 할 수준

  • 전체 80% 이상 커버리지: 일반적으로 좋음으로 간주됨
  • 90% 이상 중요한 경로: 중요한 비즈니스 로직은 충분히 테스트되어야 함
  • 100% 유틸리티 함수: 순수 함수와 유틸리티는 완전히 테스트하기 쉬움
  • UI 구성요소의 낮은 커버리지: 통합 테스트가 필요할 수 있으므로 허용 가능한 경우 많음

모범 사례

양보다 질에 집중

ts
// 좋음: 실제 기능 테스트
test("calculateTax 는 다른 세율을 처리해야 합니다", () => {
  expect(calculateTax(100, 0.08)).toBe(8);
  expect(calculateTax(100, 0.1)).toBe(10);
  expect(calculateTax(0, 0.08)).toBe(0);
});

// 피하기: 커버리지를 위해 단순히 줄만 실행
test("calculateTax 가 존재합니다", () => {
  calculateTax(100, 0.08); // 단언 없음!
});

엣지 케이스 테스트

ts
test("사용자 입력 유효성 검사", () => {
  // 일반적인 경우 테스트
  expect(validateEmail("user@example.com")).toBe(true);

  // 커버리를 의미 있게 향상시키는 엣지 케이스 테스트
  expect(validateEmail("")).toBe(false);
  expect(validateEmail("invalid")).toBe(false);
  expect(validateEmail(null)).toBe(false);
});

커버리지를 사용하여 누락된 테스트 찾기

bash
# 테스트되지 않은 코드를 식별하기 위해 커버리지 실행
bun test --coverage

# 주의가 필요한 특정 파일 확인
bun test --coverage src/critical-module.ts

다른 품질 지표와 결합

커버리지는 하나의 지표일 뿐입니다. 다음도 고려하세요.

  • 코드 리뷰 품질
  • 통합 테스트 커버리지
  • 오류 처리 테스트
  • 성능 테스트
  • 타입 안전성

문제 해결

일부 파일에 커버리지가 표시되지 않음

파일이 커버리지 리포트에 표시되지 않는 경우 테스트에서 가져오지 않았을 수 있습니다. 커버리지는 실제로 로드된 파일만 추적합니다.

ts
// 테스트하려는 모듈을 가져오세요
import { myFunction } from "../src/my-module";

test("내 함수가 작동합니다", () => {
  expect(myFunction()).toBeDefined();
});

잘못된 커버리지 리포트

예상과 일치하지 않는 커버리지 리포트가 표시되는 경우.

  1. 소스 맵이 올바르게 작동하는지 확인하세요
  2. coveragePathIgnorePatterns 의 파일 패턴을 확인하세요
  3. 테스트 파일이 실제로 테스트할 코드를 가져오는지 확인하세요

대규모 코드베이스의 성능 문제

대규모 프로젝트의 경우 커버리지 수집이 테스트를 느리게 할 수 있습니다.

toml
[test]
# 커버리지가 필요하지 않은 대규모 디렉토리 제외
coveragePathIgnorePatterns = [
  "node_modules/**",
  "vendor/**",
  "generated/**"
]

개발 중 모든 테스트 실행 대신 CI 또는 특정 브랜치에서만 커버리지를 실행하는 것을 고려하세요.

Bun by www.bunjs.com.cn 편집