Loading the catalog…
Loading the catalog…
오늘 project8000에 통합 테스트를 처음 붙였다. 명령 하나를 실행하면 Postgres와 Redis 컨테이너가 뜨고, 테스트가 끝나면 알아서 사라진다. 전부 도는 데 6초쯤 걸린다. 결과만 보면 간단하다. 그런데 여기까지 곧게 오지는 못했다. 한 번 만들었다가 전부 걷어내고 다시 만들었다. 그 과정을 순서대로 적어 둔다. 시작은 질문 하나였다 Claude에게 물었다. "unit test, integration test, e2e test 중에 적용 안 된 게 있어?" 종류 상태 unit test 있다. 백엔드는 unittest로 258개, 프론트는 vitest integration test 절반만 있다 e2e test 없다 "절반만"이라는 말이 걸렸다. 라우터와 유스케이스를 함께 실행하는 테스트는 있었다. 하지만 DB와 Redis 자리에는 전부 가짜 객체가 들어가 있었다. 예를 들어 test_generation_job_queue.py 의 _FakeRedis 는 파이썬 딕셔너리로 Redis 흉내를 낸다. 그런데 실제 큐 어댑터는 Redis 안에서 Lua 스크립트를 돌린다. 가짜 객체는 Lua를 실행하지 못한다. 그러니까 그 스크립트가 진짜 Redis에서 도는지는 한 번도 확인된 적이 없었다. 그냥 Postgres를 쓸 수 없는 이유 다른 프로젝트라면 postgres 이미지를 하나 띄우면 끝난다. 이 프로젝트는 두 가지가 걸렸다. 첫째, 백엔드가 Postgres에 직접 붙지 않는다. backend/app/container.py 는 create_async_client 로 Supabase 클라이언트 하나만 만든다. 이 클라이언트는 HTTP로 통신한다. asyncpg 같은 DB 드라이버는 의존성에 없다. 둘째, 마이그레이션이 Supabase에만 있는 것들을 쓴다. 쓰는 것 뜻 쓰는 곳 auth.uid() 로그인한 사용자 id를 돌려주는 함수 001 , 003 등의 접근 정책 service_role 서버만 쓰는 DB 역할 012 부터 021 까지의 권한 부여 storage.buckets 파일 저장소 목록 테이블 009_media_storage.sql vector 벡터 검색 확장 001_init.sql 일반 Postgres 이미지에는 이 넷이 모두 없다. 나중에는 Postgres로 바꿀 거지만 지금은 현재 상태에 맞게 할 수 있는 방법을 찾기로 했다. 가벼운 방법을 찾았다 Claude가 처음 권한 건 supabase start 였다. Supabase 전체를 내 컴퓨터에 복제하는 명령이다. 컨테이너를 열 개 넘게 띄우고, 공식 문서는 RAM 7GB 이상을 권장한다. 테스트 몇 개 돌리자고 쓰기엔 무겁다. 더 가벼운 방법 세 가지를 추천해 달라고 했다. 방식 장점 걸리는 점 Supabase CLI로 DB만 띄우기 마이그레이션이 그대로 적용된다 설정 파일이 필요하다 Testcontainers 테스트가 컨테이너를 직접 관리한다 일반 이미지로는 마이그레이션이 실패한다 docker-compose에 테스트용 서비스 추가 krow에서 쓰던 방식이라 익숙하다 위와 같고, 적용 스크립트도 직접 써야 한다 Claude는 첫 번째를 추천했다. 나도 그걸 골랐다. 첫 번째 시도: Supabase CLI supabase init 으로 설정 파일을 만들고 supabase db start 를 실행했다. 이미지를 받는 데 시간이 걸렸지만 결과는 깔끔했다. 마이그레이션 21개가 오류 없이 적용됐다. 이어서 supabase/migrations/tests/ 에 있던 검증 SQL 9개를 돌렸다. 7개가 통과하고 2개가 실패했다. 처음엔 DB 구성이 잘못된 줄 알았다. 원인은 검증 SQL 쪽에 있었다. 두 파일 모두 "마이그레이션 일부만 적용된 DB"를 전제로 쓰여 있었다. 파일 실패한 이유 expression_templates.sql 테스트 데이터 4건만 있을 거라 기대했다. 실제로는 019 가 넣은 초기 데이터 72건이 함께 세어졌다 project_delete.sql generators 테이블에 값을 넣을 때 group_type 을 빼먹었다. 006 이 이 컬럼을 필수로 만든 뒤였다 이 검증 SQL들은 그동안 전체 마이그레이션이 적용된 DB에서 한 번도 실행된 적이 없었다는 뜻이다. 두 파일을 각각 두세 줄씩 고쳤고 9개가 모두 통과했다. 테스트용 DB를 만들자마자 테스트 자체의 문제가 먼저 드러난 셈이다. 내가 원한 건 이게 아니었다 여기서 확인차 물었다. "이제 통합 테스트가 돌 때 이 DB가 올라가고, 끝나면 사라지는 거지?" 아니었다. 방금 만든 건 내가 직접 띄우고 직접 내리는 DB였다. 컨테이너는 계속 떠 있었고, 내려도 데이터는 볼륨에 남았다. 게다가 통합 테스트라고 부를 코드도 아직 없었다. SQL 파일을 손으로 실행했을 뿐이다. 세 가지 방식을 비교할 때 나는 무게와 간편함만 봤다. "누가 DB를 띄우고 내리는가"는 따져 보지 않았다. 내가 원한 동작은 처음부터 두 번째 방식인 Testcontainers의 것이었다. 방향을 바꿨다. CLI 방식으로 만든 컨테이너, 볼륨, 이미지 두 개, 설정 파일을 모두 지웠다. 두 번째 시도: Testcontainers Testcontainers는 테스트 코드가 Docker 컨테이너를 직접 띄우고, 끝나면 지우는 라이브러리다. 문제는 앞에서 본 그대로였다. 일반 Postgres 이미지로는 마이그레이션이 안 된다. 그래서 Supabase가 배포하는 Postgres 이미지를 단독으로 띄워서 실험했다. 나머지 서비스 없이 DB 이미지 하나만이다. 결과가 생각보다 좋았다. 4초 만에 떴다. service_role 같은 역할도, auth.uid() 도, vector 확장도 이미 들어 있었다. 마이그레이션 21개 중 실패한 건 009_media_storage.sql 하나였다. storage.buckets 테이블은 DB 이미지가 아니라 Storage 서비스가 만들기 때문이다. 이 테이블만 테스트 준비 단계에서 미리 만들기로 했다. 여기서 한 번 더 막혔다. postgres 역할은 storage 스키마에 테이블을 만들 권한이 없었다. 관리자 역할인 supabase_admin 으로 만들고 postgres 에게 권한을 주는 것으로 풀었다. 준비 코드는 이게 전부다. def setUpModule() -> None: global db db = ( DockerContainer(IMAGE) .with_env("POSTGRES_PASSWORD", "postgres") .with_volume_mapping(MIGRATIONS, "/migrations") .waiting_for(ExecWaitStrategy([*PSQL, "-U", "postgres", "-c", "select 1"])) ) db.start() unittest.addModuleCleanup(db.stop) psql("-c", STORAGE_BUCKETS, user="supabase_admin") for path in sorted(MIGRATIONS.glob("*.sql")): psql("-f", f"/migrations/{path.name}") addModuleCleanup(db.stop) 을 컨테이너를 띄운 바로 다음 줄에 둔 데는 이유가 있다. 그 아래에서 오류가 나도 컨테이너는 지워진다. 실제로 첫 실행 때 권한 오류로 준비 단계가 실패했는데, 컨테이너는 남지 않았다. Redis 테스트는 가짜 객체 대신 실제 RedisGenerationJobQueueAdapter 를 진짜 Redis에 붙였다. 테스트는 3개다. 그중 하나는 빈 배열이 빈 배열 그대로 돌아오는지 본다. Redis의 Lua는 빈 배열을 JSON으로 바꿀 때 {} 로 바꿔 버린다. 어댑터는 JSON 원문을 통째로 보관해서 이 문제를 피한다. 이게 실제로 통하는지는 진짜 Redis에서만 확인할 수 있다. 제대로 도는지 확인했다 확인한 것 결과 통합 테스트 4개 통과. 6초에서 9초 실행 전후 컨테이너 수 12개로 같다 일부러 실패하는 SQL을 넣었을 때 테스트도 실패한다 기존 unit test 258개 그대로 실행된다. 통합 테스트는 섞이지 않는다 마지막 줄은 폴더 구조로 해결했다. 통합 테스트는 backend/tests/integration/ 에 뒀고 __init__.py 를 만들지 않았다. unittest는 __init__.py 가 없는 하위 폴더를 건너뛴다. 그래서 Docker가 없는 환경에서도 기존 테스트는 전과 똑같이 돈다. 실행 명령은 이렇다. cd backend && uv run --group dev python -m unittest discover -s tests/integration 오늘 배운 것 오늘 어긋났던 지점을 적어 둔다. "안 된다"는 말은 실험하면 범위가 줄어든다. "일반 Postgres로는 마이그레이션이 안 된다"는 맞는 말이었다. 하지만 Supabase 이미지를 직접 띄워 보니 안 되는 건 21개 중 1개였고, 테이블 하나로 해결됐다. 가장 크게 어긋난 건 내 요청이었다. 나는 "테스트용 DB"를 달라고 했다. 정작 원한 건 "테스트가 시작할 때 뜨고 끝나면 사라지는 DB"였다. 이걸 처음부터 말했다면 첫 번째 시도는 없었을 것이다. 다만 첫 번째 시도에서 검증 SQL 2개의 문제를 찾았으니 헛걸음만은 아니었다. 아직 남은 것 저장소 어댑터( SupabaseCanvasRepository 등)는 아직 테스트하지 못한다. HTTP로 접속하기 때문에 PostgREST 컨테이너가 필요하다. PostgREST는 HTTP 요청을 SQL로 바꿔 주는 서버다. storage.buckets 는 컬럼 5개짜리 대역이다. 파일 저장소 동작까지 검증하려면 Storage 서비스 컨테이너를 추가해야 한다. 통합 테스트는 아직 CI에서 돌지 않는다. e2e 테스트는 여전히 없다.
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
테스트할 때만 떴다가 사라지는 DB를 만들었다. 오늘 project8000에 통합 테스트를 처음 붙였다. 명령 하나를 실행하면 Postgres와 Redis 컨테이너가 뜨고, 테스트가 끝나면 알아서 사라진다. 전부 도는 데 6초쯤 걸린다. 결과만 보면 간단하다. 그런데 여기까지 곧게 오지는 못했다. 한 번 만들었다가 전부 걷어내고 다시 만들었다. 그 과정을 순서대로 적어 둔다. 시작은 질문 하나였다 Claude에게 물었다. "unit test, integration test, e2e test 중에 적용 안 된 게 있어?" 종류 상태 unit test 있다. 백엔드는 unittest로 258개, 프론트는 vitest integration test 절반만 있다 e2e test 없다 "절반만"이라는 말이 걸렸다.…
Open source