유닛 테스트
이제 실제 Nodebird의 코드를 테스트해봅시다. middlewares.js에 있는 isLoggedIn과 isNotLoggedIn 함수를 테스트해보겠습니다.
routes/middlewares.test.js
const { isLoggedIn, isNotLoggedIn } = require("./middlewares");
describe("isLoggedIn", () => {
test("로그인되어 있으면 isLoggedIn이 next를 호출해야 함", () => {});
test("로그인되어 있지 않으면 isNotLoggedIn이 에러를 응답해야 함", () => {});
});
describe("isNotLoggedIn", () => {
test("로그인되어 있으면 isNotLoggedIn이 에러를 응답해야 함", () => {});
test("로그인되어 있지 않으면 isNotLoggedIn이 next를 호출해야 함", () => {});
});
isLoggedIn 함수와 isNotLoggedIn 함수를 불러와 네 개의 테스트를 작성했습니다. 아직 내용은 입력하지 않았습니다. describe 함수는 처음 보는 것일 텐데요. 테스트를 처음 보는 것일 텐데요. 테스트를 그룹화해주는 역할을 합니다. test 함수가 마찬가지로 첫 번째 인수는 그룹에 대한 설명, 두 번째 인수인 함수는 그룹에 대한 내용입니다.
테스트 내용을 작성하기에 앞서 잠깐 middlewares.js를 다시 보고 오겠습니다.
routes/middlewares.js
exports.isLoggedId = (req, res, next) => {
if (req.isAuthenticated()) {
next();
} else {
res.status(403).send("로그인 필요");
}
};
exports.isNotLoggedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
next();
} else {
const message = encodeURIComponent("로그인한 상태입니다.");
res.redirect(`/?error=${message}`);
}
};
실제 코드에서는 익스프레스가 req, res 객체와 next 함수를 인수로 넣었기에 사용할 수 있지만, 테스트 환경에서는 어떻게 넣아야 할지 고민됩니다. req 객체에는 isAuthenticated 메서드가 존재하고 res 객체에도 status, send, redirect 메서드가 존재하는데, 코드가 성공적으로 실행되게 하려면 이것들을 모두 구현해야 합니다.
이럴 때는 과감하게 가짜 객체와 함수를 만들어 넣으면 됩니다. 텍스트의 역할은 코드나 함수가 제대로 실행되는지를 검사하고 값이 일치하는지를 검사하는 것이므로, 테스트 코드의 객체가 실제로 익스프레스 객체가 아니어도 됩니다. 어떻게 가짜 객체, 가짜 함수를 넣는 행위를 모킹(mocking)이라고 합니다.
routes/middlewares.test.js
const { isLoggedIn, isNotLoggedIn } = require("./middlewares");
describe("isLoggedIn", () => {
const res = {
status: jest.fn(() => res),
send: jest.fn(),
}
const next = jest.fn();
test("로그인되어 있으면 isLoggedIn이 next를 호출해야 함", () => {
const req = {
isAuthenticated: jest.fn(() => true),
}
isLoggedIn(req, res, next);
expect(next).toBeCalledTimes(1);
});
test("로그인되어 있지 않으면 isNotLoggedIn이 에러를 응답해야 함", () => {
const req = {
isAuthenticated: jest.fn(() => false),
};
isLoggedIn(req, res, next);
expect(res.status).toBeCalledWith(403);
expect(res.send).toBeCalledWith("로그인 필요");
});
});
describe("isNotLoggedIn", () => {
test("로그인되어 있으면 isNotLoggedIn이 에러를 응답해야 함", () => {});
test("로그인되어 있지 않으면 isNotLoggedIn이 next를 호출해야 함", () => {});
});
먼저 isLoggedIn부터 테스트해보겠습니다. req, res, next를 모킹했습니다. 함수를 모킹할 때는 1ess)n 메서드를 사용합니다. 합수의 반환값을 지정하고 싶다면 Jest. fn() => 반환값)을 사용 하면 됩니다. isAuthenticated는 로그인 여부를 알려주는 함수이므로 테스트 내용에 따라 true나 talse를 반환하고, Tes status는 res. status (403).send('he 10'>처럼 메서드 체이닝이 가능해야 하므로 res를 반환하고 있습니다.
실제로는 reg나 res 객체에 많은 속성과 메서드가 들어 있겠지만, 지금 테스트에서는 1SAutien ticated나 status, send만 사용하므로 나머지는 과감하게 제외하면 됩니다.
test 함수 내부에서는 모킹된 객체와 함수를 사용해 isLoggedIn 미들웨어를 호출한 후 expect로 원하는 내용대로 실행되었는지 체크하면 됩니다. toBeCalledTimes(숫자)는 정확하게 몇 번 호출 되었는지를 체크하는 메서드고, toBeCalledWith(인수)는 특정 인수와 함께 호출되었는지를 체크 하는 메서드입니다.
테스트를 돌려보면 모두 통과합니다.
$ npm test
> nodebird@0.0.1 test
> jest
(node:16856) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
PASS routes/middlewares.test.js
isLoggedIn
√ 로그인 되어있으면 isLoggedIn이 next를 호출해야 함 (3ms)
√ 로그인 되어있지 않으면 isLoggedIn이 에러를 응답해야 함 (1ms)
isNotLoggedIn
√ 로그인되어 있으면 isNotLoggedIn이 에러를 응답해야 함
√ 로그인되어 있지 않으면 isNotLoggedIn이 next를 호출해야 함
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 5.634s
Ran all test suites.
원하는 결과가 실행되었으므로 테스트를 통과합니다. 황당하지만, 작성하지 않는 두 개의 테스트도 통과합니다. 이것이 테스트를 한다고 해서 에러가 없음을 보장할 수 없는 이유입니다. 테스트 대상을 잘못 선정하거나 잘못된 방식으로 테스트한 경우에는 테스트를 작성했더라도 에러가 발생할 수 있습니다. 테스트를 올바르게 작성하는 데는 많은 훈련과 연습이 필요합니다.
isNotLoggedIn 부분은 다음 NODE JS 글에서 계속하갰습니다.
'프로그래밍 언어 > NODE JS' 카테고리의 다른 글
| 유닛 테스트(3) (0) | 2025.12.23 |
|---|---|
| 유닛 테스트(2) (0) | 2025.12.20 |
| 노드 서비스 테스트하기 - 테스트 준비하기 (0) | 2025.12.13 |
| CORS 이해하기 (0) | 2025.12.11 |
| 사용량 제한 구현하기 (0) | 2025.12.04 |