๋ฉ”์ธ ์ฝ˜ํ…์ธ ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ
Fixture DB์˜ ๋ฐ์ดํ„ฐ๋ฅผ Test DB๋กœ ๋™๊ธฐํ™”ํ•˜์—ฌ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ์ค€๋น„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.

Fixture ๋™๊ธฐํ™” ๊ฐœ์š”

์™„์ „ ๋ณต์‚ฌ

๋ชจ๋“  ๋ฐ์ดํ„ฐ์Šคํ‚ค๋งˆ + ๋ ˆ์ฝ”๋“œ

๊นจ๋—ํ•œ ์‹œ์ž‘

Test DB ์ดˆ๊ธฐํ™”์ผ๊ด€๋œ ํ™˜๊ฒฝ

๋น ๋ฅธ ์‹คํ–‰

pg_dump + pg_restoreํšจ์œจ์ ์ธ ๋ณต์‚ฌ

์ž๋™ ์‹คํ–‰

import ํ›„ ์ž๋™์ˆ˜๋™ ์‹คํ–‰ ๊ฐ€๋Šฅ

pnpm sonamu fixture sync

Fixture DB์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ Test DB๋กœ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

pnpm sonamu fixture sync
์ด ๋ช…๋ น์–ด๋Š”:
  1. Test DB๋ฅผ ์™„์ „ํžˆ ์ดˆ๊ธฐํ™”
  2. Fixture DB๋ฅผ ๋คํ”„
  3. Test DB์— ๋ณต์›

์ž‘๋™ ์›๋ฆฌ

๋‚ด๋ถ€ ๊ตฌํ˜„

// sonamu/src/testing/fixture-manager.ts
async function sync() {
  const fixtureConn = Sonamu.dbConfig.fixture.connection;
  const testConn = Sonamu.dbConfig.test.connection;
  
  // 1. Test DB ์—ฐ๊ฒฐ ์ข…๋ฃŒ
  execSync(`psql -h ${testConn.host} -p ${testConn.port} -U ${testConn.user} 
    -d postgres -c "
      SELECT pg_terminate_backend(pg_stat_activity.pid)
      FROM pg_stat_activity
      WHERE datname = '${testConn.database}'
        AND pid <> pg_backend_pid();
    "`);
  
  // 2. Test DB ์žฌ์ƒ์„ฑ
  execSync(`psql -h ${testConn.host} -U ${testConn.user} -d postgres 
    -c "DROP DATABASE IF EXISTS \\"${testConn.database}\\""`);
  
  execSync(`psql -h ${testConn.host} -U ${testConn.user} -d postgres 
    -c "CREATE DATABASE \\"${testConn.database}\\""`);
  
  // 3. Fixture DB โ†’ Test DB ๋ณต์‚ฌ
  const dumpCmd = `pg_dump -h ${fixtureConn.host} -p ${fixtureConn.port} 
    -U ${fixtureConn.user} -d ${fixtureConn.database} -Fc`;
  
  const restoreCmd = `pg_restore -h ${testConn.host} -p ${testConn.port} 
    -U ${testConn.user} -d ${testConn.database} --no-owner --no-acl`;
  
  execSync(`${dumpCmd} | PGPASSWORD="${testConn.password}" ${restoreCmd}`);
}

์‹คํ–‰ ๊ณผ์ •

$ pnpm sonamu fixture sync

# 1. ๊ธฐ์กด ์—ฐ๊ฒฐ ์ข…๋ฃŒ
Terminating existing connections to myapp_test...

# 2. Test DB ์žฌ์ƒ์„ฑ
DROP DATABASE IF EXISTS "myapp_test"
CREATE DATABASE "myapp_test"

# 3. Fixture DB ๋คํ”„
pg_dump -h fixture-db.example.com -d myapp_fixture -Fc

# 4. Test DB ๋ณต์›
pg_restore -h localhost -d myapp_test --no-owner --no-acl

โœ… Sync complete!

์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค

1. Fixture ๋ณ€๊ฒฝ ํ›„

# Fixture์— ์ƒˆ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€
pnpm sonamu fixture import User 10,11,12

# ์ž๋™์œผ๋กœ sync ์‹คํ–‰๋จ
# ํ•˜์ง€๋งŒ ์ˆ˜๋™์œผ๋กœ๋„ ๊ฐ€๋Šฅ:
pnpm sonamu fixture sync

2. Test DB ์ดˆ๊ธฐํ™”

# Test DB๊ฐ€ ์˜ค์—ผ๋˜์—ˆ์„ ๋•Œ
# (์˜ˆ: ์ˆ˜๋™์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•œ ๊ฒฝ์šฐ)
pnpm sonamu fixture sync

# ๊นจ๋—ํ•œ Fixture ๋ฐ์ดํ„ฐ๋กœ ์žฌ์„ค์ •

3. ํŒ€์› ๊ฐ„ ๋™๊ธฐํ™”

# ํŒ€์› A๊ฐ€ Fixture์— ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€
# (์›๊ฒฉ Fixture DB์— ์ €์žฅ๋จ)

# ํŒ€์› B๊ฐ€ ๋กœ์ปฌ Test DB์— ๋ฐ˜์˜
pnpm sonamu fixture sync

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋น„๊ต

๋™๊ธฐํ™” ์ „

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   Fixture DB        โ”‚
โ”‚ (์›๊ฒฉ ์„œ๋ฒ„)          โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Users: 10 rows      โ”‚
โ”‚ Posts: 50 rows      โ”‚
โ”‚ Comments: 200 rows  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    Test DB          โ”‚
โ”‚ (๋กœ์ปฌ)              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Users: 5 rows       โ”‚  โ† ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ
โ”‚ Posts: 20 rows      โ”‚
โ”‚ Comments: 80 rows   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๋™๊ธฐํ™” ํ›„

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   Fixture DB        โ”‚
โ”‚ (์›๊ฒฉ ์„œ๋ฒ„)          โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Users: 10 rows      โ”‚
โ”‚ Posts: 50 rows      โ”‚
โ”‚ Comments: 200 rows  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    Test DB          โ”‚
โ”‚ (๋กœ์ปฌ)              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Users: 10 rows      โ”‚  โ† ๋™๊ธฐํ™”๋จ!
โ”‚ Posts: 50 rows      โ”‚
โ”‚ Comments: 200 rows  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

pg_dump ์˜ต์…˜

-Fc (Format Custom)

๋ฐ”์ด๋„ˆ๋ฆฌ ํ˜•์‹์œผ๋กœ ๋คํ”„ํ•˜์—ฌ ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.
# -Fc: Custom format (์••์ถ•๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ)
pg_dump -d myapp_fixture -Fc
์žฅ์ :
  • ์••์ถ•๋˜์–ด ํฌ๊ธฐ๊ฐ€ ์ž‘์Œ
  • pg_restore๋กœ ์„ ํƒ์  ๋ณต์› ๊ฐ€๋Šฅ
  • ๋น ๋ฅธ ์†๋„

โ€”no-owner โ€”no-acl

์†Œ์œ ์ž์™€ ๊ถŒํ•œ ์ •๋ณด๋ฅผ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค.
pg_restore -d myapp_test --no-owner --no-acl
์ด์œ :
  • ๋กœ์ปฌ๊ณผ ์›๊ฒฉ์˜ ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ
  • ๊ถŒํ•œ ์ถฉ๋Œ ๋ฐฉ์ง€

์ž๋™ vs ์ˆ˜๋™

์ž๋™ ๋™๊ธฐํ™”

pnpm sonamu fixture import ์‹คํ–‰ ์‹œ ์ž๋™์œผ๋กœ sync๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค:
async function fixture_import(entityId: string, recordIds: number[]) {
  await setupFixtureManager();
  
  // 1. Import
  await FixtureManager.importFixture(entityId, recordIds);
  
  // 2. Sync (์ž๋™)
  await FixtureManager.sync();
}
$ pnpm sonamu fixture import User 1,2,3

# Import ์™„๋ฃŒ ํ›„ ์ž๋™์œผ๋กœ:
โœ… Import complete! Syncing to test DB...
# Sync ์‹คํ–‰...

์ˆ˜๋™ ๋™๊ธฐํ™”

ํ•„์š”ํ•  ๋•Œ ์ง์ ‘ ์‹คํ–‰:
# Test DB๋ฅผ Fixture DB ์ƒํƒœ๋กœ ์žฌ์„ค์ •
pnpm sonamu fixture sync

์›Œํฌํ”Œ๋กœ์šฐ

์ผ๋ฐ˜์ ์ธ ๊ฐœ๋ฐœ ํ๋ฆ„

# 1. ํ”„๋กœ๋•์…˜์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
pnpm sonamu fixture import User 1,2,3
# โ†’ ์ž๋™์œผ๋กœ sync ์‹คํ–‰๋จ

# 2. ํ…Œ์ŠคํŠธ ์‹คํ–‰
pnpm test

# 3. ํ•„์š”์‹œ ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
pnpm sonamu fixture import Post 10,11,12
# โ†’ ์ž๋™์œผ๋กœ sync ์‹คํ–‰๋จ

# 4. ํ…Œ์ŠคํŠธ ์žฌ์‹คํ–‰
pnpm test

Fixture ๊ณต์œ  ํ๋ฆ„

# ํŒ€์› A
pnpm sonamu fixture import User 100,101,102
# โ†’ Fixture DB(์›๊ฒฉ)์— ์ €์žฅ๋จ

# ํŒ€์› B
pnpm sonamu fixture sync
# โ†’ Fixture DB์—์„œ ๋กœ์ปฌ Test DB๋กœ ๋ณต์‚ฌ

# ํŒ€์› B๋„ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋กœ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ

์„ฑ๋Šฅ ์ตœ์ ํ™”

1. ๋กœ์ปฌ Fixture DB

Fixture DB๋ฅผ ๋กœ์ปฌ์—์„œ ์šด์˜ํ•˜๋ฉด sync๊ฐ€ ๋น ๋ฆ…๋‹ˆ๋‹ค:
// sonamu.config.json
{
  "db": {
    "fixture": {
      "client": "pg",
      "connection": {
        "host": "localhost",  // ๋กœ์ปฌ
        "database": "myapp_fixture"
      }
    },
    "test": {
      "client": "pg",
      "connection": {
        "host": "localhost",
        "database": "myapp_test"
      }
    }
  }
}

2. ์ตœ์†Œ ๋ฐ์ดํ„ฐ

Fixture์— ํ•„์š”ํ•œ ์ตœ์†Œ ๋ฐ์ดํ„ฐ๋งŒ ์œ ์ง€:
# โœ… ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•: ํ•„์š”ํ•œ ๊ฒƒ๋งŒ
pnpm sonamu fixture import User 1,2,3

# โŒ ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ•: ๋„ˆ๋ฌด ๋งŽ์€ ๋ฐ์ดํ„ฐ
pnpm sonamu fixture import User 1,2,3,...,1000

๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

1. ์ •๊ธฐ์ ์ธ ๋™๊ธฐํ™”

# ๋งค์ผ ์•„์นจ ์ตœ์‹  Fixture๋กœ ๋™๊ธฐํ™”
pnpm sonamu fixture sync

# ํ…Œ์ŠคํŠธ ์‹คํ–‰
pnpm test

2. CI/CD ํ†ตํ•ฉ

# .github/workflows/test.yml
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      
      - name: Setup PostgreSQL
        run: |
          docker run -d -p 5432:5432 \
            -e POSTGRES_PASSWORD=postgres \
            postgres:14
      
      - name: Initialize Fixture
        run: pnpm sonamu fixture init
      
      - name: Sync Fixture
        run: pnpm sonamu fixture sync
      
      - name: Run Tests
        run: pnpm test

3. ์Šคํฌ๋ฆฝํŠธ ์ถ”๊ฐ€

// package.json
{
  "scripts": {
    "test:setup": "pnpm sonamu fixture sync",
    "test": "pnpm test:setup && vitest"
  }
}
# ํ…Œ์ŠคํŠธ ์ „ ์ž๋™์œผ๋กœ sync
pnpm test

๋ฌธ์ œ ํ•ด๊ฒฐ

์—ฐ๊ฒฐ ์‹คํŒจ

Error: connection to server at "fixture-db.example.com" failed
ํ•ด๊ฒฐ:
  • ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ํ™•์ธ
  • Fixture DB ์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ
  • ๋ฐฉํ™”๋ฒฝ ์„ค์ • ํ™•์ธ

๊ถŒํ•œ ์˜ค๋ฅ˜

Error: must be owner of database myapp_test
ํ•ด๊ฒฐ:
-- Test DB ์†Œ์œ ์ž ๋ณ€๊ฒฝ
ALTER DATABASE myapp_test OWNER TO current_user;

DB๊ฐ€ ์‚ฌ์šฉ ์ค‘

Error: database "myapp_test" is being accessed by other users
ํ•ด๊ฒฐ:
-- ๋ชจ๋“  ์—ฐ๊ฒฐ ์ข…๋ฃŒ
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = 'myapp_test'
  AND pid <> pg_backend_pid();
๋˜๋Š”:
# ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ค‘์ง€ ํ›„ ๋‹ค์‹œ ์‹œ๋„
pnpm sonamu fixture sync

์ฃผ์˜์‚ฌํ•ญ

Fixture ๋™๊ธฐํ™” ์‹œ ์ฃผ์˜์‚ฌํ•ญ:
  1. Test DB ์ดˆ๊ธฐํ™”: ๊ธฐ์กด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ชจ๋‘ ์‚ญ์ œ๋จ
  2. ๊ถŒํ•œ ํ•„์š”: Test DB์— ๋Œ€ํ•œ DROP/CREATE ๊ถŒํ•œ
  3. ์—ฐ๊ฒฐ ์ข…๋ฃŒ: ์‹คํ–‰ ์ค‘์ธ ํ…Œ์ŠคํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์‹คํŒจ
  4. ๋„คํŠธ์›Œํฌ: Fixture DB๊ฐ€ ์›๊ฒฉ์ด๋ฉด ์‹œ๊ฐ„์ด ๊ฑธ๋ฆผ
  5. ๋ฐ์ดํ„ฐ ํฌ๊ธฐ: Fixture๊ฐ€ ํฌ๋ฉด sync๊ฐ€ ๋А๋ฆผ

๋‹ค์Œ ๋‹จ๊ณ„