Bun 의 테스트 러너는 이제 내장 코드 커버리지 리포팅을 지원합니다. 이를 통해 코드베이스의 얼마나 많은 부분이 테스트로 커버되는지 쉽게 확인하고 현재 충분히 테스트되지 않은 영역을 찾을 수 있습니다.
커버리지 활성화
bun:test 는 어떤 코드 줄이 테스트로 커버되는지 확인할 수 있습니다. 이 기능을 사용하려면 CLI 에 --coverage 를 전달하세요. 콘솔에 커버리지 리포트를 출력합니다.
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 에 다음 줄을 추가하세요.
[test]
# 항상 커버리지 활성화
coverage = true기본적으로 커버리지 리포트는 테스트 파일을 포함하고 소스맵을 제외합니다. 이것이 일반적으로 원하는 것이지만 bunfig.toml 에서 다르게 구성할 수 있습니다.
[test]
coverageSkipTestFiles = true # 기본값 false커버리지 임계값
bunfig.toml 에 커버리지 임계값을 지정할 수 있습니다. 테스트 스위트가 이 임계값을 충족하거나 초과하지 못하면 bun test 는 실패를 나타내기 위해 0 이 아닌 종료 코드로 종료됩니다.
간단한 임계값
[test]
# 90% 줄 단위 및 함수 단위 커버리지가 필요한 경우
coverageThreshold = 0.9상세 임계값
[test]
# 줄과 함수에 대해 다른 임계값 설정
coverageThreshold = { lines = 0.9, functions = 0.9, statements = 0.9 }이러한 임계값 중 하나를 설정하면 fail_on_low_coverage 가 활성화되어 커버리지가 임계값 미만일 경우 테스트 실행이 실패합니다.
커버리지 리포터
기본적으로 커버리지 리포트는 콘솔에 출력됩니다.
CI 환경 및 기타 도구의 지속적인 코드 커버리지 리포트를 위해 --coverage-reporter=lcov CLI 옵션이나 bunfig.toml 의 coverageReporter 옵션을 전달할 수 있습니다.
[test]
coverageReporter = ["text", "lcov"] # 기본값 ["text"]
coverageDir = "path/to/somewhere" # 기본값 "coverage"사용 가능한 리포터
| 리포터 | 설명 |
|---|---|
text | 콘솔에 커버리지의 텍스트 요약을 출력합니다 |
lcov | lcov 형식으로 커버리지를 저장합니다 |
LCOV 커버리지 리포터
lcov 리포트를 생성하려면 lcov 리포터를 사용할 수 있습니다. 이는 커버리지 디렉토리에 lcov.info 파일을 생성합니다.
[test]
coverageReporter = "lcov"# 또는 CLI 를 통해
bun test --coverage --coverage-reporter=lcovLCOV 형식은 다양한 도구 및 서비스에서 널리 지원됩니다.
- 코드 에디터: VS Code 확장 프로그램은 인라인으로 커버리지를 표시할 수 있습니다
- CI/CD 서비스: GitHub Actions, GitLab CI, CircleCI
- 커버리지 서비스: Codecov, Coveralls
- IDE: WebStorm, IntelliJ IDEA
GitHub Actions 에서 LCOV 사용
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커버리지에서 파일 제외
테스트 파일 건너뛰기
기본적으로 테스트 파일 자체는 커버리지 리포트에 포함됩니다. 다음을 사용하여 제외할 수 있습니다.
[test]
coverageSkipTestFiles = true # 기본값 false이렇게 하면 테스트 패턴 (예: *.test.ts, *.spec.js) 과 일치하는 파일이 커버리지 리포트에서 제외됩니다.
특정 경로 및 패턴 무시
coveragePathIgnorePatterns 를 사용하여 특정 파일이나 파일 패턴을 커버리지 리포트에서 제외할 수 있습니다.
[test]
# 단일 패턴
coveragePathIgnorePatterns = "**/*.spec.ts"
# 여러 패턴
coveragePathIgnorePatterns = [
"**/*.spec.ts",
"**/*.test.ts",
"src/utils/**",
"*.config.js"
]이 옵션은 glob 패턴을 허용하며 Jest 의 collectCoverageFrom 무시 패턴과 유사하게 작동합니다. 이러한 패턴 중 하나와 일치하는 파일은 텍스트 및 LCOV 출력 모두에서 커버리지 계산 및 리포팅에서 제외됩니다.
일반적인 사용 사례
[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.coverageIgnoreSourcemaps 를 true 로 설정하세요. 이는 고급 사용 사례 외에는 거의 바람직하지 않습니다.
[test]
coverageIgnoreSourcemaps = true # 기본값 false커버리지 기본값
기본적으로 커버리지 리포트는 다음을 수행합니다.
- 제외
node_modules디렉토리 - 제외 비 JS/TS 로더를 통해 로드된 파일 (예:
.css,.txt). 단, 커스텀 JS 로더가 지정된 경우 제외 - 포함 테스트 파일 자체 (
coverageSkipTestFiles = true로 비활성화 가능) coveragePathIgnorePatterns로 추가 파일 제외 가능
고급 구성
커스텀 커버리지 디렉토리
[test]
coverageDir = "coverage-reports" # 기본값 "coverage"여러 리포터
[test]
coverageReporter = ["text", "lcov"]특정 테스트 패턴과 함께 커버리지
# 특정 테스트 파일에서만 커버리지 실행
bun test --coverage src/components/*.test.ts
# 이름 패턴으로 커버리지 실행
bun test --coverage --test-name-pattern="API"CI/CD 통합
GitHub Actions 예시
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: trueGitLab CI 예시
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 구성요소의 낮은 커버리지: 통합 테스트가 필요할 수 있으므로 허용 가능한 경우 많음
모범 사례
양보다 질에 집중
// 좋음: 실제 기능 테스트
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); // 단언 없음!
});엣지 케이스 테스트
test("사용자 입력 유효성 검사", () => {
// 일반적인 경우 테스트
expect(validateEmail("user@example.com")).toBe(true);
// 커버리를 의미 있게 향상시키는 엣지 케이스 테스트
expect(validateEmail("")).toBe(false);
expect(validateEmail("invalid")).toBe(false);
expect(validateEmail(null)).toBe(false);
});커버리지를 사용하여 누락된 테스트 찾기
# 테스트되지 않은 코드를 식별하기 위해 커버리지 실행
bun test --coverage
# 주의가 필요한 특정 파일 확인
bun test --coverage src/critical-module.ts다른 품질 지표와 결합
커버리지는 하나의 지표일 뿐입니다. 다음도 고려하세요.
- 코드 리뷰 품질
- 통합 테스트 커버리지
- 오류 처리 테스트
- 성능 테스트
- 타입 안전성
문제 해결
일부 파일에 커버리지가 표시되지 않음
파일이 커버리지 리포트에 표시되지 않는 경우 테스트에서 가져오지 않았을 수 있습니다. 커버리지는 실제로 로드된 파일만 추적합니다.
// 테스트하려는 모듈을 가져오세요
import { myFunction } from "../src/my-module";
test("내 함수가 작동합니다", () => {
expect(myFunction()).toBeDefined();
});잘못된 커버리지 리포트
예상과 일치하지 않는 커버리지 리포트가 표시되는 경우.
- 소스 맵이 올바르게 작동하는지 확인하세요
coveragePathIgnorePatterns의 파일 패턴을 확인하세요- 테스트 파일이 실제로 테스트할 코드를 가져오는지 확인하세요
대규모 코드베이스의 성능 문제
대규모 프로젝트의 경우 커버리지 수집이 테스트를 느리게 할 수 있습니다.
[test]
# 커버리지가 필요하지 않은 대규모 디렉토리 제외
coveragePathIgnorePatterns = [
"node_modules/**",
"vendor/**",
"generated/**"
]개발 중 모든 테스트 실행 대신 CI 또는 특정 브랜치에서만 커버리지를 실행하는 것을 고려하세요.