안녕하세요, 이중혁입니다

배우고 경험한 기술들을 하나씩 정리하는 공간

Jest & Husky 통합

Jest 테스트 프레임워크와 Husky Git Hooks를 활용한 자동화된 테스트 및 품질 관리 시스템입니다.

JestHuskyGit Hooks

구현 내용

Jest & Husky 통합

대규모 리포에서도 안정적으로 통과하는 커밋. Husky로 Git Hooks를 자동화하고,Jest로 핵심 로직을 빠르게 검증합니다. 커밋 전 품질 게이트를 통과해야만 코드가 저장되며, 팀 전체가 동일한 기준으로 개발 품질을 유지합니다.

핵심 목표

  • 품질 게이트: 커밋 전에 Lint/테스트 강제
  • 빠른 피드백: 테스트 병렬 실행과 캐시로 속도 확보
  • 일관성: 모든 개발자 동일 훅/설정 공유
  • 로컬 품질 관리: 개발 환경에서 즉시 품질 검증

Husky 설정

  • pre-commit: ESLint + Jest 전체 테스트 실행
  • prepare 스크립트: husky 초기화 자동화
  • 간단한 구조: 에러 시 자동 중단으로 안정성 확보
  • pnpm 기반: 빠른 패키지 매니저로 성능 최적화

데이터 플로우

  • 1단계: 개발자가 변경 후 커밋 시도
  • 2단계: Husky가 pre-commit 훅에서 ESLint + Jest 실행
  • 3단계: 통과 시 커밋 완료, 실패 시 중단 및 수정
  • 4단계: 로컬에서 품질 검증 완료

시스템 아키텍처

Husky - Git Hooks Automation
  • • pre-commit에서 ESLint/Jest 실행
  • • 실패 시 커밋 중단
  • • 팀 전체 동일 정책 적용
Jest - Test Orchestration
  • • 유닛/통합 테스트 실행
  • • 커버리지 측정
  • • ts-jest 트랜스파일
성능 최적화
  • @swc/jest: SWC 기반 빠른 트랜스파일
  • forceExit: 열린 핸들 문제 해결로 안정성 확보
  • detectOpenHandles: 메모리 누수 감지 및 방지
  • Extension 로드: 커스텀 확장 함수들로 테스트 편의성 향상
import type { Config } from 'jest';

const config: Config = {
  testTimeout: 100000,
  moduleFileExtensions: ['js', 'json', 'ts'],
  rootDir: '.',
  testRegex: '.*\.spec\.ts$',
  transform: {
    '^.+\.ts$': '@swc/jest',
  },
  collectCoverageFrom: ['**/*.ts'],
  modulePathIgnorePatterns: ['<rootDir>/dist/'],
  coverageDirectory: './coverage',
  testEnvironment: 'node',
  roots: ['<rootDir>/apps/', '<rootDir>/libs/'],
  moduleNameMapper: {
    '^@libs/dao(|/.*)$': '<rootDir>/libs/dao/src/$1',
    '^@libs/common(|/.*)$': '<rootDir>/libs/common/src/$1',
    '^@extension(|/.*)$': '<rootDir>/libs/common/src/extension/$1',
  },
  setupFilesAfterEnv: [
    '<rootDir>/jest.setup.ts', // 전역 폴리필 로드
  ],
  forceExit: true, // 강제 종료 허용
  detectOpenHandles: true, // 열린 핸들 감지
};

export default config;

Swagger API 문서화

NestJS와 Swagger를 활용한 자동화된 API 문서 생성 및 인터랙티브 문서 시스템입니다.

SwaggerAPI DocumentationNestJS

구현 내용

Swagger API 문서화

개발자가 작성한 코드에서 자동으로 API 문서를 생성하고, 프론트엔드 개발자나 외부 파트너가 인터랙티브하게 테스트할 수 있는 시스템입니다. 표준화된 API 문서를 제공하며, 인증, 검증, 예제 등이 자동으로 포함됩니다.

핵심 기능

  • 자동 문서 생성: 코드에서 API 스펙 추출
  • 인터랙티브 테스트: 브라우저에서 직접 API 호출
  • 타입 안전성: DTO와 실제 API 스펙 동기화
  • 인증 지원: JWT, Bearer 토큰 등 자동 처리
  • 검증 규칙: class-validator와 연동

데코레이터 활용

  • @ApiTags: API 그룹 분류
  • @ApiOperation: 엔드포인트 설명
  • @ApiResponse: 응답 스키마
  • @ApiBody: 요청 본문 스키마
  • @ApiProperty: 필드 설명 및 예제
  • validation: class-validator 연동

시스템 아키텍처

NestJS Application
  • • Controller 데코레이터 수집
  • • DTO 스키마 분석
  • • API 스펙 생성
Swagger UI
  • • API 스펙 렌더링
  • • API 테스트 인터페이스
  • • 인증 토큰 관리
배포 & 프록시
  • 보안 고려사항: 환경별 접근 제어
  • IP 화이트리스트: 특정 IP만 접근
  • Basic Auth: 추가 인증 레이어
  • HTTPS 강제: 보안 연결
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { SWAGGER_CUSTOM_OPTIONS } from '@libs/common/constants/swagger.constants';
import {
  ENVIRONMENT,
  NODE_ENV,
} from '@libs/common/constants/environment.constants';

/**
 * OPEN API(Swagger) 초기화
 */
private _initializeSwagger(): void {
  if (NODE_ENV != ENVIRONMENT.PRODUCTION) {
    const config = new DocumentBuilder()
      .setTitle('Game Server')
      .setDescription('API description')
      .setVersion('1.0')
      .addApiKey(
        {
          type: 'apiKey',
          name: 'X-API-KEY',
          in: 'header',
          description: 'api',
        },
        'apiKey',
      )
      .addBasicAuth(
        {
          type: 'http',
          name: 'Authorization',
          in: 'header',
          description: 'Username: email & Password: password',
        },
        'basic',
      )
      .addBearerAuth(
        {
          type: 'http',
          name: 'Authorization',
          in: 'header',
          description: 'refresh token',
        },
        'jwt-refresh',
      )
      .addBearerAuth(
        {
          type: 'http',
          name: 'Authorization',
          in: 'header',
          description: 'jwt auth',
        },
        'jwt',
      )
      .addBearerAuth({ type: 'http' }, 'kakao-token')
      .build();

    const document = SwaggerModule.createDocument(this.app, config);

    SwaggerModule.setup(
      'game/api-docs',
      this.app,
      document,
      SWAGGER_CUSTOM_OPTIONS,
    );
  }
}