처음 테스트를 작성하기 위해 jest에서 어떻게 테스트하는지 깃허브를 찾아다니면서 Express로 구현된 프로젝트의 테스트 코드를 파헤쳐다녔다.
하나 참고가 될 것 같은 코드를 봤는데, supertest를 활용해 테스트를 진행하고 있었다.
supertest로 테스트를 진행하면 Request에 대한 내용을 작성하면 내가 작성한 서버의 로직을 돌고 Response 객체를 가져오게 된다.
yarn add -D supertest regenerator-runtime
supertest를 async/await로 진행할 것이기 때문에 regenerator-runtime
를 함께 받아준다. 이전에는 @babel/pollyfill를 사용해 런타임 문제를 해결했다고 하는데 deprecated 경고가 뜬다. 찾아보니 regenerator-runtime
로 해결할 수 있다고 한다.
여기서 app.js에 다음과 같은 코드를 넣어 준다.
if (process.env.NODE_ENV !== "test") {
app.listen(port, () => {
logger.info(`Start server at ${port}`);
});
}
이렇게 하지 않으면 jest가 테스트 코드를 병렬적으로 진행할 때, 이미 포트가 사용 중이라고 테스트가 종료되어버린다. test 환경에서 실제로 실행되지 않도록 한다.
import "regenerator-runtime";
import request from "supertest";
import server from "../app.js";
먼저, 패지키를 불어온다. app.js
에서 Express app을 가져온다.
it("생성된 포스트 get", async () => {
const res = await request(server) // 1
.get("/api/posts/" + postId) // 2
.send(); // 3
});
코드를 보면, 일단 비동기로 처리되기 때문에 await으로 실행되는 결과를 기다리도록 한다. 만약 async/await이 익숙하지 않다면 Promise 체인으로도 가능하다.
Request에 사용할 수 있는 함수들이 여러가지 존재한다. 인증을 위해 .set("authorization", token)
와 같은 것도 붙일 수 있고, post의 경우 send 내에 객체를 통해 body를 전달할 수 있다.
또한 이미지 전달에 대한 테스트를 진행할 땐, attach를 통해 원하는 파일을 담아 테스트할 수 있다. 다만 이 땐, send를 사용하지 않고 field와 함께 사용한다.
const res = await request(app)
.post("/api/posts")
.set("authorization", token)
.field("title", "title")
.field("contents", "content")
.field("wideAddr", "서울특별시")
.field("localAddr", "강남구")
.attach("photos", pwd + "/1.JPG");
res에는 해당 Request에 따른 Response 객체가 저장된다.
그럼 이제 받아온 Response 객체를 통해 값을 검증한다.
it("생성된 포스트 get", async () => {
const res = await request(server)
.get("/api/posts/" + postId)
.send();
expect(res.statusCode).toEqual(201);
expect(Object.keys(res.body)).toEqual(
expect.arrayContaining(["title", "contents", "author"])
);
expect(res.body.title).toEqual("title");
expect(res.body.author).toEqual("sinf");
});
이것은 기존에 jest를 통해 값을 검증하는 것과 같다.
다만 res.body에 값이 담겨오는 것, res.statusCode에 상태코드가 저장되어 있는 것 기억하면 된다.
값을 테스트하는 것을 더 다양한 방법이 있을 것이다.