[개발 블로그 제작기] 5. 서버 생성 & TDD 세팅

김현우·2021년 9월 16일

서버는 기본적으로 Express.js, Typescript으로 만듭니다.
DB는 MySQL, Sequelize ORM을 사용합니다.
테스팅 라이브러리는 Mocha, Chai, Supertest를 사용합니다.
그리고 개발 환경에서의 편리한 서버 구동을 위해 nodemon을 사용합니다.

프로젝트 생성

프로젝트가 될 폴더를 만들고 (저는 nullsafety-be라고 지었습니다)

npm init -y

위 명령어로 package.json파일을 만듭니다.

그리고 express를 받아주고, TS환경에서 만들 거니까 ts-node를 받아줍니다.

npm i express ts-node

이제 타입스크립트, 테스팅 라이브러리, nodemon을 받습니다.

npm i -D typescript chai mocha supertest nodemon @types/chai @types/mocha @types/supertest @typs/node @types/express

이것저것 받았으니 package.json의 dependencies와 devDependencies에 기록이 다 되었겠죠.
이제 아래 명령어로 tsconfig.json파일을 만듭니다.

tsc --init

tsc를 찾을 수 없다는 에러가 뜨면 아래 명령어로 대체합니다.

npx tsc --init

서버 진입점 파일 생성

이제 서버의 진입점, app.ts를 만듭니다.
근데 바로 띡 만들지 말고, 프로젝트 구조 관리를 위해 src폴더를 만들고 거기에 app.ts를 둡니다. 그리고 다음과 같이 작성합니다.

/src/app.ts

import { NextFunction, Request, Response } from "express";

const express = require("express");
const app = express();

// node 환경변수에 지정해놓은 포트번호가 있으면 그걸로.
// 없다면 5000번 포트로. (5000이 아니어도 됩니다)
app.set("port", process.env.PORT || 5000);

// 서버에 들어온 유효한 요청을 처리하는 router를 만들어서 끼워줍니다.
// 이제 바로 만들건데, 바로 만들거니까 만들었다고 치고 코드 먼저 작성해 줍니다.
app.use("/", require("./routes/rootRouter"));

// 클라이언트가 요청하는 경로가 위 라우터에 있는 경로가 아니라면
// router middleware를 그냥 지나서 이곳으로 오겠죠. 즉 여기는 404 Not Found를 담당하는 미들웨어입니다.
app.use((req: Request, res: Response, next: NextFunction) => {
  const err: any = new Error("Not Found");
  err.status = 404;
  next(err);
});

// 에러 발생 시 처리하는 미들웨어
app.use((err: any, req: Request, res: Response, next: NextFunction) => {
  res.status(err.status || 500);
  if (err.message === "Not Found") res.send("404 Not Found");
  else res.send("Internal server error");
});

app.listen(app.get("port"), () => {
  console.log(`Listen at `, app.get("port"));
});

module.exports = app;

router 생성

실제 프로젝트 소스가 될 테니 좀 전에 만든 src 폴더에 만듭니다.
라우터가 위 코드에서는 하나밖에 없지만 여러개로 분할할 지도 모릅니다. 그래서 /src/routes폴더를 만들어서 여기에 라우터 파일을 만듭니다.

/src/routes/rootRouter.ts

import { Request, Response } from "express";

const router = require("express").Router();

router.get("/", (req: Request, res: Response) => {
  res.send("Hello");
});

module.exports = router;

아직은 루트경로(/)에 대해 그냥 "Hello"만 응답합니다. 본격적인 기능 개발은 나중에 하고, 오늘은 서버 잘 돌아가는 지 보고 테스팅을 세팅할겁니다.

서버 실행

node는 typescript파일을 실행하지 못합니다.
그래서 아까 ts-node를 따로 받았습니다.
node가 아닌 ts-node에게 app.ts를 실행하라고 해야 합니다.

package.json

...

 "scripts": {
    "start": "ts-node ./src/app.ts",
  },

...

터미널에

npm start

명령을 입력해서 서버를 실행시켜 봅니다.
잘 될 겁니다.
브라우저에서 localhost:5000 주소로 접속해 봅니다.
Hello가 뜰 겁니다.

nodemon 개발 서버 적용

node 혹은 ts-node로 서버를 실행하면, 개발 중 서버 소스를 수정했을 때 직접 서버를 재시동해줘야 합니다. nodemon은 소스 변경 시 자기가 알아서 재시동 해줍니다. nodemon은 아까 받았고, package.json에 nodemon으로 서버를 실행하는 script만 넣어주면 됩니다.

...

 "scripts": {
    "start": "ts-node ./src/app.ts",
    "dev": "nodemon --exec ts-node src/app.ts"
  },

...

테스트 작성

테스트코드를 작성해서 서버를 테스트를 해봅시다.
테스트코드는 /__test__폴더를 만들어서 따로 모아두려고 합니다.
특정 기능 말고, 무슨 서버든 일단 서버라면 이건 해야지! 하는 점들이 있습니다. app.spec.ts 파일을 만들어 그런 사항들을 테스트하는 코드를 작성하겠습니다.
일단 유효한 URL로 요청 시 응답을 잘 하는지, 잘못된 요청을 했을 때 에러 응답을 똑바로 하는지 테스트합니다.

/__test__/app.spec.ts

import { expect, should } from "chai";
import { describe, it } from "mocha";
import request from "supertest";
const app = require("../src/app");

describe("[Invalid URL]", () => {
  it("GET: Invalid URL", () => {
    request(app)
      .get("/invalid")
      .expect(404)
      .end((err, res) => {
        expect(res.text).to.equal("404 Not Found");
      });
  });
  it("POST: Invalid URL", () => {
    request(app)
      .post("/invalid")
      .expect(404)
      .end((err, res) => {
        expect(res.text).to.equal("404 Not Found");
      });
  });
});

describe("[Basic App]", () => {
  it("GET: /", () => {
    request(app)
      .get("/")
      .expect(200)
      .end((err, res) => {
        expect(res.text).to.equal("Hello");
      });
  });
});

테스트 실행

테스트 코드를 실행하는 script를 package.json에 추가합니다.

...

 "scripts": {
    "test": "mocha __test__/**/*.ts -r ts-node/register",
    "start": "ts-node ./src/app.ts",
    "dev": "nodemon --exec ts-node src/app.ts"
  },

...

이제 테스트를 실행해 봅니다.

npm run test

mocha가 테스트를 잘 수행했고 겨우 통과했네요!

다음 포스트에선 공짜로 배포할 곳을 정해서, 오늘 작성한 초기상태의 서버를 배포하고 배포자동화까지 적용해 보겠습니다.

0개의 댓글