테스트 DB 세팅

김동현·2024년 7월 12일

테스트코드

목록 보기
6/7

통합테스트

사내에서 통합 테스트를 진행하기 위해 Test를 위한 DB를 Docker-compose로 말아 사용하기로 했다!

기존에 존재하는 서비스에서 통합 테스트를 구현하는 데 도움이 될 수 있는테스트 전용 DB를 구축하는 방법을 기술해보려고 한다.
기술 스택은 Nestjs, Typescript, MariaDB에서 세팅한 기준이다!

Docker-compose.yml

먼저, Docker-compose.yml 파일을 먼저 구성해보자
테스트 코드를 실행할 때 사용할 DB 컨테이너를 생성하기 위한 환경 파일이다.

version: '3.7'

services:
  maria:
    container_name: wd-mysql-container			// 1
    image: mariadb:latest					    // 2
    ports:
      - "33306:3306"							// 3
    environment:
      MYSQL_USER: ${TEST_DB_USER}				// 해당 ${} 내의 변수는 env 파일내 값을 따른다.
      MYSQL_PASSWORD: ${TEST_DB_PASSWORD}       // process.env를 생각하면 된다.
      MYSQL_ROOT_PASSWORD: ${TEST_DB_PASSWORD}
      MYSQL_DATABASE: ${TEST_DB_DATABASE}
    volumes:									// 4 
      - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql 
  1. 컨테이너 이름을 해당 값으로 설정
  2. 이미지는 Mariadb:latest(최신) 이미지를 사용
  3. 로컬 Port 33306 과 컨테이너 포트 3306을 매핑
  4. 컨테이너와 호스트 간의 파일을 공유하는 방법
  • MariaDB 이미지는 컨테이너가 처음 실행 될 때 특정 경로에 있는 스크립트를 자동으로 실행한다.
  • 그 경로가 /docker-entrypoint-initdb.d/init.sql이다. << 즉, ./sql/init.sql에 있는 파일을 자동으로 실행하는 경로에 공유함으로써 init.sql 파일이 자동으로 실행되는 것이다.
  • 각 init.sql 파일의 경로를 적어주면 된다. << docker-compose.yml 파일이 존재하는 경로 기준 상대 경로이다.

init.sql

테스트를 진행하기 위해 테스트용 DB에 권한을 부여, 기본 테이블 생성 및 기본 데이터 생성을 위한 SQL 파일이다.

docker-compose.yml의 volume 부분에 의해 컨테이너가 생성되면 아래의 sql 파일이 최초로 실행된다!

추가 레퍼런스는 해당 블로그를 참고하면 도움이 많이 될 것이다!

-- init.sql

-- 사용자가 존재하는지 확인합니다.
SELECT User FROM mysql.user WHERE User = 'test';

-- 사용자가 존재하는 경우에만 삭제합니다.
DROP USER IF EXISTS 'test'@'%';

CREATE USER 'test'@'%' IDENTIFIED BY 'test';
GRANT ALL PRIVILEGES ON *.* TO 'test'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

-- 권한 설정

-- 테이블 세팅
CREATE TABLE ..
-- 디폴트 데이터 세팅(어드민 유저 또는 일반 유저)
INSERT ...

package.json

...
  "------------ e2e TEST-----------------------": "",
  "test:e2e:pre": "docker-compose up -d", // 통합 테스트 전 테스트 디비 실행
  "test:e2e:done": "docker-compose down", // 통합 테스트 마무리 후 컨테이너 삭제
  "test:e2e": "npm run test:e2e:pre && npx cross-env NODE_ENV=test jest --config ./test/jest-e2e.json --detectOpenHandles && npm run test:e2e:done" // 통합 테스트 실행
...

npm/yarn run test:e2e를 실행하면 npm run test:e2e:pre CLI가 먼저 실행된다.
사전 실행 CLI는 docker-compose up -d로 docker-compose.yml을 기준으로 -d 백그라운드 컨테이너를 생성한다.
이 후 테스트 코드를 실행하게 된다.
테스트 코드가 끝나고 npm run test:e2e:done CLI가 호출되어 컨테이너가 down 된다!

  1. npm run test:e2e:pre << 도커 컨테이너 생성
  2. npm run test:e2e << 테스트 코드 실행
  3. npm run test:done << 도커 컨테이너 삭제

가장 기본적인 테스트 데이터베이스 세팅할 수 있는 방법이다.
env 파일 내에 환경변수는 위 도커 파일 기준으로는 아래와 같이 세팅하면 된다.

TEST_DB_HOST=localhost
TEST_DB_USER=test
TEST_DB_PORT=33306
TEST_DB_PASSWORD=test
TEST_DB_DATABASE=wdietdb

P.S

테스트 코드에 대해 찾아 보다 테스트 시 DB 의존 처리 + 필요한 만큼 테스트 환경 만들기 유튜브 영상을 보게 되었다.

직전 영상에서는 유닛 테스트에 대한 생각을 나눠주셨고
위 링크는 추가로 나온 유닛 테스트 시 DB 의존을 어떻게 처리하는 지에 대해 생각을 나누어주신 영상이었다.

회사에서 테스트 코드에 대해 이야기를 나눌 때 공통으로 나눈 이야기가 DB와의 통신까지 테스트가 이루어 져야 되지 않겠냐 였다.
그렇기에 유닛 테스트보다 통합 테스트를 먼저 구현해 나가자는 결론을 내렸었다.

그 과정에서 TestContainer 구축 비용이나 Test DB Schema에 대한 고려는 없었다.
모두가 테스트 코드에 대해 지식이 완전하지 않아서 생각 자체를 나눌 수 없었던 부분이었다.

영상에서 가장 와닿았던 부분은 효율 및 현실공유 자원에 대한 이야기였다.

공유 자원(테스트 데이터베이스의 스키마를 누가 관리할 것인가)

A: 테스트 성공 후 배포 예정
B: 그 사이 Test DB 스키마 변경 및 배포
A: Test 실패로 인한 배포 실패

효율과 현실

--- 테스트 수행 속도 좋음 / 현실과 멈
mock
H2
TestContainer
rad-DB
--- 현실과 가까움 / 테스트 수행 속도 느림(비교적)

외부와의 의존성

마지막 부분에서 WIFI가 끊기더라도 성공하는 테스트를 구현하는 것을 주요하게 생각하신다고 하셨다.
외부와 서버와 네트워킹이 필요한 테스트가 있다고 할 때 테스트 도중 네트워크가 불안정하여 테스트가 실패한다면 배포의 실패로도 연결된다.
<< 해당 의견도 상당히 설득력이 있었다.
내부 컨테이너로 말아 올리는 것에는 적용되지 않을 수 있지만 third-party API를 통해 데이터를 받아오는 경우라면 고려해야 하는 사항일 것 같았다.

이어지는 두 영상을 보며 테스트 코드 그 중 유닛테스트에 대한 새로운 관점을 갖게 된 시간이었다.

출근 후 해당 영상을 공유하며 의견을 다시 나누어 보는 시간을 가질 필요가 있을 것 같다 😀

profile
달려보자

0개의 댓글