2022.07.25 - [IT] - [Nomad Corders] NestJS로 API 만들기 #2.4 to #2.7 정리
#3 UNIT TESTING
#3.0 Introduction to Testing in Nest
package.json 파일에 보면 테스팅과 관련된 5개 항목을 볼 수 있음.
jest : 자바스크립트를 아주 쉽게 테스팅하는 npm 패키지.
"Jest is a delightful JavaScript Testing Framework with a focus on simplicity."
.spec.ts : test module을 포함한 파일.
ex) movies controller를 테스트하기 위해서는 movies.controller.spec.ts 파일이 있어야함.
NestJs에서는 jest가 .spec.ts 파일들을 찾아볼 수 있도록 설정되어 있음.
[>npm run test:cov]를 통해서 테스트 결과 값과 coverage(적용 범위) 값을 알 수 있음.
"test:cov":"jest --coverage"
테스트 PASS/FAIL 로 결과가 나옴.
[>npm run test:watch]를 입력하면 Watch Usage로 어떤 것을 실행할 것인지 물어봄.
"test:watch":"jest --watch"
a를 눌러 파일에 변경점이 있을 때 마다 모든 테스트를 실행.
* Unit Testing : 모든 function을 따로 테스트하는 것. 서비스에서 분리된 유닛을 테스트하는 것.
* End-to-End(e2e) Testing : Whole System Testing. 전체 시스템 테스팅.
ex) Unit Testing은 getAll() or getOne() 등 function 하나씩 테스트할 때 사용.
ex) e2e Testing은 이 페이지로 가면 특정 페이지가 나와야하는 경우 사용. 사용자가 사용할만한 것들을 테스트.
#3.1 Your first Unit Test
movies.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { MoviesService } from './movies.service';
describe('MoviesService', () => {
let service: MoviesService;
beforeEach(async () => { //테스트 하기 전에 실행되는 곳
const module: TestingModule = await Test.createTestingModule({
providers: [MoviesService],
}).compile();
service = module.get<MoviesService>(MoviesService);
});
it('should be defined', () => { //it : indivisual test
expect(service).toBeDefined();
});
//let me create
it("should be 4", () => {
expect(2+2).toEqual(4) //2+2가 4와 같기(toEqual)를 기대(expect)하고 있어
} )
});
파일을 위와 같이 수정하고, test:watch를 통해서 단위테스트를 해보자.
실행결과 우리가 추가한 should be 4가 문제없이 pass됨.
만약, expect(2+2).toEqual(5) 요렇게 바꾸면,
테스트에 실패했다고 나오고, 어떤 값이 나와야하는지까지 알려줌.
#3.2 Testing getAll and getOne
그럼 이제, 우리가 movies.service.ts 에서 사용하고 있는 함수들의 Unit Test 단위 테스트를 작성해보자.
요 다섯가지 함수에 관한 단위테스트를 작성해 볼게~
[getAll 함수 테스트]
//getAll 함수의 결과값이 Array 인지 테스트
describe("getAll", () => {
it("should return an array", () => {
const result = service.getAll();
expect(result).toBeInstanceOf(Array);
});
});
[getOne 함수 테스트]
//getOne 함수 실행 테스트
describe("getOne", () => {
//결과값이 정상적으로 나오는지 테스트
it("should return a movie", () => {
//테스트를 위한 Movie 만들기 (없으면 에러)
service.create({
title:'Test Movie',
genres: ['test'],
year: 2000,
});
const movie = service.getOne(1);
expect(1).toBeDefined();
expect(movie.id).toEqual(1);
});
//에러가 정상적으로 나오고 있는지 테스트
it("should throw 404 error", () => {
try {
service.getOne(999);
}catch(e){
expect(e).toBeInstanceOf(NotFoundException)
expect(e.message).toEqual('Movie with ID 999 not found.');
}
});
});
coverage가 전보다 증가. 테스트 코드가 늘어나서 그럼.
Funcs 결과값을 보면 이 수치들이 어느 정도의 파일들을 테스트하고 있는지 알려줌.
#3.3 Testing delete and create
[deleteOne 함수 테스트]
//deleteOne 함수 실행 테스트
describe("deleteOne", () => {
//삭제가 정상적인지 테스트
it("deletes a movie", () => {
//테스트를 위한 Movie 만들기 (없으면 에러)
service.create({
title:'Test Movie',
genres: ['test'],
year: 2000,
});
const beforeDelete = service.getAll().length;
service.deleteOne(1);
const afterDelete = service.getAll().length;
//삭제 후의 Movie 개수 비교
expect(afterDelete).toBeLessThan(beforeDelete);
});
//에러가 정상적으로 나오고 있는지 테스트
it("should return a 404", () => {
try {
service.deleteOne(999);
}catch(e){
expect(e).toBeInstanceOf(NotFoundException)
}
});
});
[create 함수 테스트]
//create 함수 실행 테스트
describe("create", () => {
it("should create a movie", () => {
const beforeCreate = service.getAll().length;
service.create({
title:'Test Movie',
genres: ['test'],
year: 2000,
});
const afterCreate = service.getAll().length;
//create 후의 Movie 개수 비교
expect(afterCreate).toBeGreaterThan(beforeCreate);
});
});
#3.4 Testing update
- (참고) 위에서 계속 각 단위테스트마다 Movie를 생성해줬는데, 미리 한 번에 생성하고 싶으면 beforeEach 안에서 만들어 주면 됨.
beforeEach(async () => { //테스트 하기 전에 실행되는 곳
const module: TestingModule = await Test.createTestingModule({
providers: [MoviesService],
}).compile();
service = module.get<MoviesService>(MoviesService);
service.create({
title:'Test Movie',
genres: ['test'],
year: 2000,
});
});
[update 함수 테스트]
//update 함수 실행 테스트
describe("update", () => {
it("should update a movie", () => {
service.create({
title:'Test Movie',
genres: ['test'],
year: 2000,
});
service.update(1, {title: 'Updated Test'});
const movie = service.getOne(1);
expect(movie.title).toEqual('Updated Test');
});
//에러가 정상적으로 나오고 있는지 테스트
it("should throw a NotFoundException", () => {
try {
service.update(999, {title: 'Updated Test'});
}catch(e){
expect(e).toBeInstanceOf(NotFoundException)
}
});
});
[최종 movies.service.spec.ts 코드]
import { Test, TestingModule } from '@nestjs/testing';
import { MoviesService } from './movies.service';
import { NotFoundException } from '@nestjs/common';
describe('MoviesService', () => {
let service: MoviesService;
beforeEach(async () => { //테스트 하기 전에 실행되는 곳
const module: TestingModule = await Test.createTestingModule({
providers: [MoviesService],
}).compile();
service = module.get<MoviesService>(MoviesService);
});
it('should be defined', () => { //it : indivisual test
expect(service).toBeDefined();
});
//getAll 함수의 결과값이 Array 인지 테스트
describe("getAll", () => {
it("should return an array", () => {
const result = service.getAll();
expect(result).toBeInstanceOf(Array);
});
});
//getOne 함수 실행 테스트
describe("getOne", () => {
//결과값이 정상적으로 나오는지 테스트
it("should return a movie", () => {
//테스트를 위한 Movie 만들기 (없으면 에러)
service.create({
title:'Test Movie',
genres: ['test'],
year: 2000,
});
const movie = service.getOne(1);
expect(1).toBeDefined();
expect(movie.id).toEqual(1);
});
//에러가 정상적으로 나오고 있는지 테스트
it("should throw 404 error", () => {
try {
service.getOne(999);
}catch(e){
expect(e).toBeInstanceOf(NotFoundException)
expect(e.message).toEqual('Movie with ID 999 not found.');
}
});
});
//deleteOne 함수 실행 테스트
describe("deleteOne", () => {
//삭제가 정상적인지 테스트
it("deletes a movie", () => {
//테스트를 위한 Movie 만들기 (없으면 에러)
service.create({
title:'Test Movie',
genres: ['test'],
year: 2000,
});
const beforeDelete = service.getAll().length;
service.deleteOne(1);
const afterDelete = service.getAll().length;
//삭제 후의 Movie 개수 비교
expect(afterDelete).toBeLessThan(beforeDelete);
});
//에러가 정상적으로 나오고 있는지 테스트
it("should return a 404", () => {
try {
service.deleteOne(999);
}catch(e){
expect(e).toBeInstanceOf(NotFoundException)
}
});
});
//create 함수 실행 테스트
describe("create", () => {
it("should create a movie", () => {
const beforeCreate = service.getAll().length;
service.create({
title:'Test Movie',
genres: ['test'],
year: 2000,
});
const afterCreate = service.getAll().length;
//create 후의 Movie 개수 비교
expect(afterCreate).toBeGreaterThan(beforeCreate);
});
});
//update 함수 실행 테스트
describe("update", () => {
it("should update a movie", () => {
service.create({
title:'Test Movie',
genres: ['test'],
year: 2000,
});
service.update(1, {title: 'Updated Test'});
const movie = service.getOne(1);
expect(movie.title).toEqual('Updated Test');
});
//에러가 정상적으로 나오고 있는지 테스트
it("should throw a NotFoundException", () => {
try {
service.update(999, {title: 'Updated Test'});
}catch(e){
expect(e).toBeInstanceOf(NotFoundException)
}
});
});
});
모든 함수에 대한 테스트가 완료됐기 때문에 100퍼센트로 나옴.
+ (추가)
spec.ts 파일에는 beforeEach 이외에도, afterEach, beforeAll, afterAll 같은 것이 있음.
예를 들어, afterAll() 안에는 DB를 깨끗하게 정리해주는(모두 지우는) function을 넣을 수 있음.
나중에 활용 가능.
이번에는 Unit Testing을 다뤘으면, 다음시간에는 test 폴더를 통해 e2e Testing을 해보자.
2022.07.27 - [IT] - [Nomad Corders] NestJS로 API 만들기 #4 정리 (완강)
'IT > DEV Study' 카테고리의 다른 글
[VB] Dictionary Add & Remove Test (feat. LINQ 람다식) (0) | 2022.09.13 |
---|---|
[Nomad Corders] NestJS로 API 만들기 #4 정리 (완강) (1) | 2022.07.27 |
[Nomad Corders] NestJS로 API 만들기 #2.4 to #2.7 정리 (413) | 2022.07.25 |
[Nomad Corders] NestJS로 API 만들기 #2.0 to #2.3 정리 (409) | 2022.07.25 |
[Nomad Corders] NestJS로 API 만들기 #0, #1 정리 (2) | 2022.07.25 |