Fixture DB์ ๋ฐ์ดํฐ๋ฅผ Test DB๋ก ๋๊ธฐํํ์ฌ ํ
์คํธ ํ๊ฒฝ์ ์ค๋นํ๋ ๋ฐฉ๋ฒ์ ์์๋ด
๋๋ค.
Fixture ๋๊ธฐํ ๊ฐ์
์์ ๋ณต์ฌ
๋ชจ๋ ๋ฐ์ดํฐ ์คํค๋ง + ๋ ์ฝ๋
๊นจ๋ํ ์์
Test DB ์ด๊ธฐํ ์ผ๊ด๋ ํ๊ฒฝ
๋น ๋ฅธ ์คํ
pg_dump + pg_restore ํจ์จ์ ์ธ ๋ณต์ฌ
์๋ ์คํ
import ํ ์๋ ์๋ ์คํ ๊ฐ๋ฅ
pnpm sonamu fixture sync
Fixture DB์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ Test DB๋ก ๋ณต์ฌํฉ๋๋ค.
๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
์ด ๋ช
๋ น์ด๋:
- Test DB๋ฅผ ์์ ํ ์ด๊ธฐํ
- Fixture DB๋ฅผ ๋คํ
- 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
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋น๊ต
pg_dump ์ต์
๋ฐ์ด๋๋ฆฌ ํ์์ผ๋ก ๋คํํ์ฌ ๋น ๋ฅด๊ณ ํจ์จ์ ์
๋๋ค.
# -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๊ฐ ๋๋ฆผ
๋ค์ ๋จ๊ณ
ํ
์คํธ DB
ํ
์คํธ DB ์ค์
Fixture ์์ฑ
fixture.ts ์์ฑํ๊ธฐ
Fixture ๋ก๋ฉ
ํ๋ก๋์
๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
ํ
์คํธ ์์ฑ
ํ
์คํธ ๊ตฌ์กฐ ์ดํดํ๊ธฐ