적용) Unit Test

yunny·2023년 1월 24일
0

westudy

목록 보기
12/15

지금까지 서버 가동에 필요한 모든 코드를 app.js에 포함했다면,
이제는 app.jsserver.js로 분리하여 관리한다

app.js

router, middleware 관련 코드만 남겨두고
app을 리턴하는 createApp 함수 생성

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 };

server.js

app은 app.js에서 만들어 놓은 createApp 함수 활용
AppDataSource.initialize(), app.listen()을 담고 있는 startServer 함수 실행

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();

서버를 켤 때는 server.js 실행
테스트 코드에서는 createApp 함수의 리턴값인 app만 활용

테스트용 dotenv 설정

테스트를 진행할 때, 실제 DB를 활용하면 문제가 발생하기 때문에
테스트 전용 환경 변수를 따로 관리해야 함

# .env.test

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

jest를 이용하게 되면 DB커넥션에 활용할 수 있다

$ npm i --save-dev supertest

해당 파일을 config로 테스트할 수 있도록 package.json/scripts에 명령어 추가

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

Unit Test 작성

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

jest 설치 및 적용(supertest)

test.js

// tests/user.test.js

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

supertest 사용

회원가입 API의 Unit Test

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();
  });

DB와의 연결 및 불필요한 데이터 삭제
테스트 이후 DB 연결 끊어주기

작성한 코드에 맞게 모든 케이스 테스트 하기

  • failed : invalid email
  • success : created user
  • failed : duplicated email
  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" });
  });
});

HTTP 메소드, 보내야 하는 정보, 예상 결과에 맞게 테스트 진행

profile
기록하지 않으면 잊어버려요 !

0개의 댓글