컨테이너 설정은 다했으니 TypeORM과 Jest의 설정을 해보자.
Data-Source.ts
일단 나는 DataSource방식으로DAO코드를 작성했다.
https://orkhan.gitbook.io/typeorm/docs/data-source
import 'reflect-metadata';
import { DataSource } from 'typeorm';
import dotenv from 'dotenv';
dotenv.config();
const { NODE_ENV, DB_USER, DB_PASSWORD } = process.env;
export const AppDataSource = new DataSource({
type: 'mysql',
host: 'localhost',
port: 포트,
username: DB_USER,
password: DB_PASSWORD,
database: DB이름,
synchronize: true,
logging: false,
entities: [엔티티들...],
migrations: [],
subscribers: [],
});
이런식으로 AppDataSource를 구성했고, 해당 객체의 getRepository로 DB에 접근하는 형태이다.
export default class FriendDAO {
static profileRepo = AppDataSource.getRepository(Profile);
static async addFriend(profileId: number, subProfileId: number) {
...
}
...
}
그럼 테스트코드를 작성할때 문제가 생기는데, DB랑 연결을 하려면 AppDataSource의 코드에서 포트를 분기해주어야 했다.
import 'reflect-metadata';
import { DataSource } from 'typeorm';
import dotenv from 'dotenv';
dotenv.config();
const { NODE_ENV, DB_USER, DB_PASSWORD } = process.env;
const isTestEnvironment = NODE_ENV === 'test';
const port = isTestEnvironment ? 3307 : 3306;
const db = isTestEnvironment ? '테스트db' : '메인db';
export const AppDataSource = new DataSource({
type: 'mysql',
host: 'localhost',
port: port,
username: DB_USER,
password: DB_PASSWORD,
database: db,
synchronize: true,
logging: false,
entities: [엔티티],
migrations: [],
subscribers: [],
});
NODE_ENV를 통해서 분기처리 해주었고, jest로 실행될 때만 해당 환경변수 값이 'test'가 되도록 해줄 것이다.
NODE_ENV를 jest.config.js에 등록해주자
process.env.NODE_ENV = 'test';
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/tests/*.(ts|tsx)'],
};
이제 그러면 아래 세단계를 거쳐 테스트가 가능하다.
docker-compose up -d
jest --setupFiles dotenv/config
docker-compose down
근데 너무 칠게 많으니까 간편하게 .sh파일로 관리해주자.
run-test.sh
#!/bin/bash
docker-compose up -d
jest --setupFiles dotenv/config
docker-compose down
"scripts": {
"test": "sh ./scripts/run-test.sh",
...
}
...
이렇게 하면 놀랍게도 테스트가 다 실패하는 경험을 하게 될 것이다.
컨테이너가 준비될때까지 기다리기
https://github.com/vishnubob/wait-for-it
개쩌는 형님들이 wait-for-it이라는 쉘스크립트를 준비해놨으니 레포에 가서 wait-for-it.sh를 훔쳐와보자.
#!/bin/bash
docker-compose up -d
sh ./scripts/wait-for-it.sh localhost:3307 -t 15
jest --setupFiles dotenv/config
docker-compose down
localhost:3307포트에 접속가능할때까지 최대 15초 기다리겠다는 말이다.
자 다시 npm test를 해보자!
아마 안될 것이다. 😂
MySQL을 기다리기...
컨테이너가 준비되더라도 MySQL은 준비되지 않았다.
아무래도 규모가 큰 형님이다보니 기다리는데 꽤나 시간이 걸리는듯 하다.
https://jeong-pro.tistory.com/239
약 15초 정도 sleep을 걸면 50%확률로 됐다 안됐다 한다...
그러지 말고 좀 더 좋은 방법을 사용해보자.
https://stackoverflow.com/questions/42567475/docker-compose-check-if-mysql-connection-is-ready
mysqladmin을 통해 MYSQL이 죽었는지 살았는지 확인이 가능하다!
이걸 활용해보자.
until docker container exec -it mySQLContainer mysqladmin ping -P 3306 -u root -p$DB_PASSWORD | grep "mysqld is alive" ; do
>&2 echo "MySQL is unavailable - waiting for it... "
sleep 1
done
대충 해석하면
docker container exec -it mySQLContainer mysqladmin ping -P 3306 -u root -p$DB_PASSWORD
해당 명령어 중 "mysqld is alive" 일때까지 1초를 기다린다.
근데 암호가 필요하므로 source .env를 통해 환경변수를 가져와주자.
#!/bin/bash
source ./.env
docker-compose up -d
sh ./scripts/wait-for-it.sh localhost:3307 -t 15
until docker container exec -it mySQLContainer mysqladmin ping -P 3306 -u root -p$DB_PASSWORD | grep "mysqld is alive" ; do
>&2 echo "MySQL is unavailable - waiting for it... "
sleep 1
done
jest --setupFiles dotenv/config
docker-compose down
성공!