왜 jest를 쓰고자 했나?#
이번에 개인 서버를 만들면서 테스트 위주의 개발을 해보기로 마음먹었어요.
원래라면 동작이 되는지 확인하고 쭉쭉 개발하면 됐는데, .spec.ts
파일을 만들어서 하나씩 시도하다 보니 관련 설정을 잡는데 알아보는 시간이 굉장히 길어졌어요. 지금 쏟는 이 시간이 나중에 더 빠르게 개발할 방법이라 생각하면서 배우고 있어요.
jest의 장점이야 다른 글에서 많이 설명하고 있지만 제가 생각했을 땐 정말 작은 단위로 테스트해 볼 수 있는 환경을 만들 수 있는 것이 장점이라고 생각해요. 큰 규모에 서비스에서 어떤 기능을 만들기 위해선 큰 기능부터 만들지 않고 여러 함수를 만들어서 기능을 만들어 갈 텐데요. 그럴 때 jest를 사용해서 구현한 함수 하나씩 확인해 보는 것이 정말 이상적인 개발인 것처럼 느껴졌어요. 마치 터미널로 확인하는 C나 C++ 프로그램을 만들 때와 같은 느낌으로 개발할 수 있어서 결과를 확인하기 쉬운 게 정말 좋다고 생각해요.
프론트엔드랑 백엔드를 프레임워크를 사용하면서 개발하다 보면 이런 작은 테스트를 브라우저나 포스트맨 같은 프로그램을 통해 확인하게 되더라구요.
계속 이렇게 개발하는 관성을 버려보고자 했어요. 바쁘다는 핑계로, 설정을 잡기 어렵다는 이유로 미뤄왔지만 지금 당장은 개발에 전념할 수 있는 시간이 많아서 도전해 보기로 했어요.
시간 설정을 성공하기 전 시도한 방법#
저는 jest 버전으로 ^29.5.0
을 사용하고 있어요.
env값을 테스트 환경에서 쓰는 법, ConfigService를 테스트 환경에서 쓰는 법, contants 변수들을 테스트 환경에서 사용하는 법, 하위 service들을 테스트하는 방법과 상위 서비스에서 사용하는 법 등을 jest를 사용하면서 알게 되었지만, 이번에는 시간 설정하는 법에 애를 먹어서 이걸 글로 써보자 했고 이 부분만 설명하려고 해요.
먼저 알려드릴 사실로는 테스트 환경에서 시간을 적용하는 여러 방법을 시도해도 UTC 시간으로만 나와서 개발 환경에서도 돌려봤어요. 개발 환경에서는 .env
에 TZ=Asia/Seoul
를 추가해서 yarn start
로 돌려봤을 때는 한국 시간으로 적용되어서 잘 나왔어요. 그렇지만 테스트 환경에서만 안 되는 걸 고치고 싶어서 찾아봤어요.
제가 시도했지만, 안되는 방법들을 알려드릴게요. 제가 잘 못한 건지 영향이 없는 건진 모르겠지만 해결책은 아니었어요.
pacakge.json에 있는 scripts에 환경변수 추가
pacakge.json에 test 스크립트들에 TZ=Asia/Seoul
추가를 해봤지만, 효과는 없었어요.
{
// ...중략
"test": "TZ=Asia/Seoul jest",
"test:watch": "TZ=Asia/Seoul jest --watch",
}
VS Code Extension orta의 jest 설정 추가
저는 VS Code Extension인 orta의 jest로 jest를 돌리고 있어요. 그래서 .vscode/settings.json
에 아래처럼 추가해 봤는데도 적용되지 않았어요.
// 테스트를 하나만 돌리고 싶으실 때 이 설정을 추가하세요.
"jest.runMode": {
"type": "on-demand",
},
"jest.nodeEnv": {
"TZ": "Asia/Seoul" // UTC+9로 설정하기 위한 시도
}
package.json에 있는 jest에 설정 추가
이 문제를 Gemini에게도 물어봤는데 pacakge.json
에 있는 jest 항목에 아래 코드를 추가하라고 저에게 알려줬어요. 근데 이 코드는 timezone이라는 변수를 jest가 받질 않아서 경고가 뜨고 적용되지 않아요.
"jest": {
"testEnvironment": "node", // 이건 default라 지워도 괜찮아요.
"timezone": "Asia/Seoul"
}
테스트에선 일단 해결되지만, Date 객체에 한국 시간 추가
마지막으로 이건 그냥 테스트하는 함수인 generateRandomDate
에 9를 더해주는 거였어요.
const generateRandomDate = (hour: number) => {
const today = new Date();
const minute = Math.floor(Math.random() * 59);
const second = Math.floor(Math.random() * 59);
today.setHours(9 + hour, minute, second, 0);
return today;
};
today.setHours(9 + 지정할 시간)
으로 해결했지만 이건 이 함수에만 적용한 거고 비슷한 경우에도 또 넣어줘야 할 것 같았어요. 그리고 개발 환경에서는 이미 설정한 타임존 때문에 한국 시간 + 9시간인게 문제라 다른 방법을 찾았어요.
시간 설정하는 방법#
jest에서 시간을 설정하는 방법은 아래와 같아요. 저는 테스트로 시간을 확인해야 하는 함수들이 특정 서비스 파일에 있어서 beforeEach
에 추가했어요. 만약 함수 하나에만 사용하는 경우에는 함수 실행 전에 이걸 추가하면 돼요 😃
beforeEach(async () => {
const offset = -(new Date().getTimezoneOffset() / 60);
// jest.useFakeTimers();
jest.setSystemTime(new Date().getTime() + offset * 60 * 60 * 1000);
});
afterEach(() => {
// jest.useRealTimers(); 필요한 경우 추가하세요!
});
offset 값은 -9가 나와요. 이 뜻은 현재 로컬 시간대가 UTC보다 9시간 앞서 있다는 걸 의미 해요(그렇지만 한국 시간이 적용되어서 new Date()가 나오지는 않았어요.).
getTimezoneOffset()의 반환 값이 UTC 시간에서 로컬 시간을 뺀 값이기 때문에 -9가 나와요. setSystemTime에는 계산한(현재 시간 + 시간 * 분 * 초 * 밀리초) timestamp값을 넣어줬어요.
setSystemTime 함수를 사용하시려면 두 방법 중 하나를 해야 해요.
- 주석 처리한 jest.useFakeTimers 함수를 먼저 호출해야 해요.
- package.json에 있는 "jest"에 아래 코드처럼 추가해야 해요.
"jest": {
// ...중략
"fakeTimers": {
"enableGlobally": true
}
}
시간을 직접 바꾸는 방법과 비슷하게 이제 테스트 환경에서만 시간을 변경할 수 있게 되었어요.
찾은 결과가 단순하지만 이 과정을 찾기까지 시간이 걸렸던 게 아쉽네요 🥲
JEST extension 테스트 코드 실행 단축키#
이번에 jest를 쓰면서 매번 모든 테스트가 돌아가는 게 번거롭다고 느껴졌어요. 그래서 하나만 돌아갈 수 있게 settings.json에 jest.runMode를 "type": "on-demand"
로 변경하면 원하는 것만 따로 실행할 수 있어요.
따로 실행하는 건 좋았지만, 마우스로 눌러서 일일이 실행시켜야 하는 게 번거로웠어요.
테스트 파일에서 테스트 하나만 돌리는 단축키는
command + ; + c
에요.
이 단축키를 사용할 땐 조건이 있어요.
- VS Code에 jest extension을 사용하고 있어야 해요.
command + shift + p
로Jest: Start All Runners
를 실행시켜야 해요.jest.runMode
를on-demand
로 바꿔야 해요(보통 자동은 모든 테스트를 돌리는 거라 이 단축키가 필요 없어요). 설정하는 건 위 코드라인에 적어놨어요.- 테스트 파일에서 실행하고자 하는 테스트 함수에 커서가 존재해야 해요.
Reviewing what you have learned and learning anew, you are fit to be a teacher.
— Confucius