Node.js에서 Unit Test 활용

류예린·2022년 8월 29일
1
post-custom-banner

1. 프로젝트 구조


본격적인 테스트 코드를 작성하기 전, 전체 구조를 살피는 과정이 선행되어야 한다. 테스트 코드를 계획 및 작성하는 이유는 사전에 에러를 방지하여 더 높은 품질의 소프트웨어를 제공하기 위함이다.

기능 추가, 버그 수정, 리팩토링을 진행하면서 다양한 실수가 존재할 수 있다. 따라서 개발자는 직접 의도한 대로 동작하는지 테스트 코드를 작성하여 사전에 미리 실수를 잡아내고 코드를 올바르게 수정할 수 있다.

소프트웨어 개발 전반으로 발생할 에러를 미리 찾아내는 것은, 테스트 환경이 서비스가 배포되는 실제 환경과 일치해야 한다는 것을 의미한다. 그래야만 미리 에러를 잡아내는 것에 의미가 있을 것이다.

서버 가동에 필요한 모든 코드가 app.js에 포함된 방식이 아닌, app.js와 server.js로 분리하는 방식으로 변경할 필요가 있다.

.
├── node_modules
├── src
│   ├── controllers
│   ├── models
│   │   └── data-source.js
│   ├── routes
│   ├── services
│   └── utils
├── tests
│   └── user.test.js
├── .env
├── .env.test
├── .gitignore
├── **app.js**
├── package-lock.json
├── package.json
└── **server.js**


app.js


const express = require("express");
const cors = require("cors");
const morgan = require("morgan");

const { routes } = require("./src/routes");

const createApp = () => {
  const app = express();

  app.use(express.json());
  app.use(cors());
  app.use(morgan("combined"));

  app.use(routes);

  return app;
};

module.exports = { createApp };
  1. 애플리케이션의 router, middleware 관련 코드만 남겨두고 app을 리턴하는 createApp 함수를 생성.
  2. 테스트 단계에서는 테스트용 request를 활용하기 때문에 따로 listen할 필요 없이 해당 createApp 함수만 활용.


server.js


require("dotenv").config();

const { createApp } = require("./app");
const { AppDataSource } = require("./src/models/data-source");

const startServer = async () => {
  const app = createApp();
  const PORT = process.env.PORT;

	await AppDataSource.initialize();

  app.listen(PORT, () => {
    console.log(`Listening on Port ${PORT}`);
  });
};

startServer();
  1. app은 app.js에서 만들어 놓은 createApp 함수를 활용.
  2. AppDataSource.initialize() , app.listen() 을 담고 있는 startServer 함수를 실행.
  3. 따라서 서버를 켤 때에는 server.js를 실행하고, 테스트 코드에서는 createApp 함수의 리턴 값인 app만 활용.


테스트용 dotenv 설정


테스트를 진행할 때 실제 프로덕션 환경의 데이터베이스를 활용하면 문제가 발생할 수 있다. 따라서 테스트 전용 환경 변수를 따로 관리해야 한다. jest를 이용하면 테스트를 실행할 때 다른 환경 변수 파일을 불러와 DB 커넥션에 활용할 수 있다. 따라서 테스트용 dotenv에는 테스트 환경에 맞는 값을 추가해줘야 한다.

# .env.test

DB_TYPE=mysql
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=dbpassword
DB_NAME=dbname

위와 같이 테스트용 환경 변수 파일인 .env.test를 만들어 진행한다. 그리고 jest를 활용하여 테스트를 진행할 때 해당 파일을 config로 테스트할 수 있도록 package.json scripts에 명령어를 다음과 같이 추가해줍니다.

"scripts": {
    "test": "DOTENV_CONFIG_PATH=.env.test jest --setupFiles=dotenv/config"
  },





2. Unit Test 작성


앞서 언급한 프로젝트 구조로 작성한 간단한 회원가입 API의 Unit Test를 살펴보자.

// tests/user.test.js

// npm i --save-dev supertest
const request = require("supertest");

// supertest의 request에 app을 담아 활용하기 위해 createApp 함수를 불러옵니다.
const { createApp } = require("../app");
// DB와의 커넥션을 위해 DataSource 객체를 불러옵니다.
const { myDataSource } = require("../src/models/data-source");

describe("Sign Up", () => {
  let app;

  beforeAll(async () => {
    // 모든 테스트가 시작하기 전(beforeAll)에 app을 만들고, DataSource를 이니셜라이징 합니다.
    app = createApp();
    await AppDataSource.initialize();
  });

  afterAll(async () => {
    // 테스트 데이터베이스의 불필요한 데이터를 전부 지워줍니다.
    await AppDataSource.query(`TRUNCATE users`);

    // 모든 테스트가 끝나게 되면(afterAll) DB 커넥션을 끊어줍니다.
    await AppDataSource.destroy();
  });

  test("FAILED: invalid email", async () => {
    // supertest의 request를 활용하여 app에 테스트용 request를 보냅니다.
    await request(app)
      .post("/users/signup") // HTTP Method, 엔드포인트 주소를 작성합니다.
      .send({ email: "wrongEmail", password: "password001@" }) // body를 작성합니다.
      .expect(400) // expect()로 예상되는 statusCode, response를 넣어 테스트할 수 있습니다.
      .expect({ message: "invalid email!" });
  });

  // 다음과 같이 본인이 작성한 코드에 맞춰 다양한 케이스를 모두 테스트해야 합니다.
  // 그래야 의도에 맞게 코드가 잘 작성되었는지 테스트 단계에서부터 확인할 수 있습니다!
  test("SUCCESS: created user", async () => {
    await request(app)
      .post("/users/signup")
      .send({ email: "wecode001@gmail.com", password: "password001@" })
      .expect(201);
  });

  test("FAILED: duplicated email", async () => {
    await request(app)
      .post("/users/signup")
      .send({ email: "wecode001@gmail.com", password: "password001@" })
      .expect(409)
      .expect({ message: "duplicated email" });
  });
});

위와 같이 테스트 코드를 작성한 뒤 npm test 명령어를 입력하면 아래와 같이 실행된다. 올바르게 테스트가 진행되는 것을 확인할 수 있다.

profile
helloworld
post-custom-banner

0개의 댓글