세상에 완벽한 코드는 없다. 하지만 코드를 보완할 방법은 있다. 여러가지의 테세트를 통해 모든(?) 경우의 수에 대비할 수 있다. Google Test Automation Conference에서 제안된 테스트 피라미드를 살펴보자.
출처 : https://cloud.google.com/architecture/devops/devops-tech-test-automation
구글에서 제안한 테스트 비율은 E2E(UI) testing 10%, Integration test 20%, unit test 70%다.
이제, Jest(코드를 테스트하는 라이브러리 중 하나)를 사용해 Unit Test를 작성해보자.
npm install --sav-dev jest
dev dependancy 하는 이유는 개발할 때만 사용하기 때문이다. 배포시에 사용하지 않는다.
npm i --save-dev babel-jest @babel/core @bable/present-env
// .babelrc.json 파일 생성 후 추가
{
"presets": [["@babel/preset-env", {"targets": {"node": "current"}}]],
}
// package.json
{
"scripts": {
"test": "jest",
},
}
여기까지 하면 테스트 실행할 환경이 만들어진다. 테스트를 실행할 때 모든 파일을 테스트할 필요가 없으니, 어떤 파일이 테스트 코드가 들어있는 파일인지 알려줘야 한다. 세가지 규칙 중 하나를 지켜 제스트가 알 수 있게 해준다.
__test__
폴더에 .js 확장자 파일이제 테스트 코드를 작성해보자.
it
, test
: 테스트의 가장 작은 단위, it과 test의 차이는 없다!describe
: 테스트 케이스 묶음describe
(큰 단위) 안에 it
, test
(작은 단위)가 들어간다.//calculate.js
function minus(a, b) {
if (typeof a === "number" && typeof b === "number") {
return a - b;
} else {
throw new Error("wrong input");
}
}
export default {minus}
//calculate.test.js
import {minus} from './calculate';
describe("minusTest", () => {
test("minus 9 - 5 to equal 3", () => {
expect(minus(9, 5)).toEqual(4);
});
test("no input", () => {
expect(() => minus()).toThrowError(new Error("wrong input"));
});
test("one input", () => {
expect(() => minus(1)).toThrowError(new Error("wrong input"));
});
});
에러를 new Error()로 던지게 되면 함수를 실행하는 순간 에러가 나기 때문에, 콜백함수로 넘겨야 에러가 넘어간다는 점을 기억하자.
테스트 코드를 작성했으면 run test를 한다.
npm run test
터미널에 PASS가 뜨면 성공이다!
우리 팀은 아래 에러 함수에 대한 테스트 코드를 작성했다.
const errorStatus = (statusCode, message) => {
if (!Object.keys(httpErrorStatus).includes(statusCode)) {
statusCode = 500;
}
const err = new Error(message || httpErrorStatus[statusCode]);
err.statusCode = statusCode;
throw err;
};
export default errorStatus;
테스트 코드가 반복되어 for...of를 사용했다.
describe('errorStatus', () => {
const httpErrorStatus = {
400: 'Bad Request',
...
};
//1: status코드가 있는 경우
for (const key in httpErrorStatus) {
test(`status가 ${key}인 경우`, () => {
expect(() => {
errorStatus(key, null);
}).toThrowError(new Error(httpErrorStatus[key]));
});
}
//0: status와 message가 없는 경우
test('status 없는 경우', () => {
expect(() => {
errorStatus();
}).toThrowError(new Error(httpErrorStatus[500]));
});
//-1: httpErrorStatus에 없는 statusCode가 들어왔을 경우
test('httpErrorStatus에 없는 statusCode', () => {
expect(() => {
errorStatus(800, null);
}).toThrowError(new Error(httpErrorStatus[500]));
});
});
두번째 인자로 콜백함수를 써줘야 하는데, 콜백함수를 작성하지 않아 우리 팀의 두시간이 쓱싹 지나가버렸다. 확인 또 확인하는 습관을 갖자..ㅎㅎ
이거 거의 세션 자료수준..