본문으로 바로가기
728x90
반응형
SMALL

🚀 Next.js에서 Supabase 실무 통합 테스트 환경 구축하기 (Vitest)

Next.js 프로젝트에서 Supabase 실제 DB를 대상으로 통합 테스트(Integration Test)를 작성할 때, 가장 큰 걸림돌은 환경 변수(process.env) 로딩 순서입니다. 본 가이드에서는 Vitestdotenv를 활용해 이 문제를 해결하고 실제 DB 연동까지 확인하는 완벽한 워크플로우를 소개합니다.


🛠️ 1. 필수 패키지 설치

테스트 환경을 구축하기 위해 필요한 핵심 도구들을 설치합니다. Next.js의 경로 별칭(@/)과 브라우저 환경(jsdom)을 지원하는 패키지들입니다.

PowerShell

npm install -D vitest @vitejs/plugin-react vite-tsconfig-paths jsdom dotenv @testing-library/jest-dom

⚙️ 2. Vitest 설정 (환경 변수 문제 해결)

Next.js 환경에서 import 문은 코드 실행보다 먼저 처리되어 환경 변수가 undefined로 뜨는 경우가 많습니다. 이를 방지하기 위해 setupFiles를 활용합니다.

vitest.config.ts 생성

TypeScript

import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import path from 'path';

export default defineConfig({
  plugins: [react(), tsconfigPaths()],
  test: {
    environment: 'jsdom',
    globals: true,
    // [핵심] 테스트 실행 직전 환경 변수를 먼저 로드합니다.
    setupFiles: [path.resolve(__dirname, './vitest.setup.ts')],
  },
});

vitest.setup.ts 생성

.env.test 파일을 읽어 process.env에 강제로 주입하는 셋업 파일입니다.

TypeScript

import { config } from 'dotenv';
import path from 'path';

// .env.test 파일을 로드하여 테스트 프로세스에 할당합니다.
config({ path: path.resolve(__dirname, '.env.test') });

📝 3. 환경 변수 및 스크립트 설정

테스트 전용 DB 정보를 관리하기 위해 .env.test 파일을 별도로 생성하는 것을 권장합니다.

.env.test 파일 예시

코드 스니펫

NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY=your-secret-key

package.json 스크립트 추가

JSON

"scripts": {
  "test": "vitest --config ./vitest.config.ts --mode test"
}

🧪 4. 실제 DB 통합 테스트 코드 작성

테스트 대상 파일(supabaseService.ts)과 같은 위치에 .test.ts 파일을 생성하여 관리합니다.

supabaseService.ts (원본 코드)

TypeScript

import { supabaseAdmin } from '@/lib/supabaseServer';

export const supabaseService = {
  async save(content: string) {
    const { data, error } = await supabaseAdmin
      .from('ko_grammer') // 테이블명 확인 필수
      .insert([{ content }])
      .select()
      .single();

    if (error) {
      console.error('DB 저장 실패:', error.message);
      return { success: false, error };
    }
    return { success: true, data };
  }
};

supabaseService.test.ts (테스트 코드)

실제 네트워크 통신이 발생하므로 타임아웃을 넉넉히 설정하고, 테스트 후 데이터를 삭제하는 Cleanup 로직을 포함합니다.

TypeScript

import { afterAll, describe, expect, it } from 'vitest';
import { supabaseAdmin } from '@/lib/supabaseServer';
import { supabaseService } from './supabaseService';

describe('supabaseService.save 실제 DB 통합 테스트', () => {
  const TEST_CONTENT = '테스트 코드에서 보낸 실제 데이터입니다.';

  // 테스트 종료 후 생성된 데이터를 삭제하여 DB 정결 유지
  afterAll(async () => {
    await supabaseAdmin
      .from('ko_grammer')
      .delete()
      .eq('content', TEST_CONTENT);
  });

  it('실제 Supabase DB에 데이터를 저장하고 결과를 반환해야 한다', async () => {
    // 1. 함수 실행
    const result = await supabaseService.save(TEST_CONTENT);

    // 2. 응답 값 검증
    expect(result.success).toBe(true);
    expect(result.data?.content).toBe(TEST_CONTENT);

    // 3. DB 직접 조회 교차 검증
    const { data } = await supabaseAdmin
      .from('ko_grammar')
      .select()
      .eq('id', result.data?.id)
      .single();

    expect(data).not.toBeNull();
    expect(data?.content).toBe(TEST_CONTENT);
  }, 10000); // 네트워크 통신 고려 타임아웃 10초 설정
});
728x90
반응형
LIST