정보 전달의 포스팅 보단 학습 메모 목적의 포스팅 입니다. 😢
부족한 설명과 내용에 대해 미리 양해 부탁드립니다.
npm run test:cov
- 코드가 얼마나 테스팅 됐는지 퍼센티지로 알려줌.npm run test:watch
- 저장 할 때 마다 테스트를 진행.
유닛 테스트
- 모든 함수를 따로 테스트
- 서비스에서 분리된 유닛을 테스트
- spec.ts 파일들을 찾아서 테스트 해준다.
E2E 테스트
- 모든 시스템을 테스팅
- 사용자의 관점에서의 테스팅
우선 유닛 테스트를 진행해보자
유닛테스트
import { NotFoundException } from '@nestjs/common';
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', () => {
expect(service).toBeDefined();
});
describe('getAll()', () => {
it('배열 반환 해줘', () => {
// 1. getAll 호출
const result = service.getAll();
// 2. result가 Array인지 테스트
expect(result).toBeInstanceOf(Array);
});
});
describe('getOne()', () => {
it('영화 반환 해줘', () => {
// 한 개의 영화 목록에 대한 테스트를 위해 데이터를 생성
service.create({
title: 'testMovie',
year: 2022,
genres: ['액션', '코미디'],
});
const movie = service.getOne(1);
// 영화 객체가 반환 되는지 여부
expect(movie).toBeDefined();
// 영화의 아이디가 1인지의 여부
expect(movie.id).toEqual(1);
});
it('해당 영화가 없으면 404에러 던져줘', () => {
try {
service.getOne(999);
} catch (e) {
expect(e).toBeInstanceOf(NotFoundException);
expect(e.message).toEqual('Movie with ID: 999');
}
});
describe('deleteOne()', () => {
it('영화 지워줘', () => {
service.create({
title: 'testMovie',
year: 2022,
genres: ['액션', '코미디'],
});
const beforeDelete = service.getAll();
service.deleteOne(1);
const afterDelete = service.getAll();
expect(afterDelete.length).toEqual(beforeDelete.length - 1);
});
it('삭제 할 영화 없으면 404에러 던져줘', () => {
try {
service.deleteOne(9999);
} catch (e) {
expect(e).toBeInstanceOf(NotFoundException);
expect(e.message).toEqual('Movie with ID: 9999');
}
});
});
describe('create()', () => {
it('영화 만들어줘', () => {
const beforeCreate = service.getAll().length;
service.create({
title: 'testMovie',
year: 2022,
genres: ['액션', '코미디'],
});
const afterCreate = service.getAll().length;
expect(afterCreate).toBeGreaterThan(beforeCreate);
});
});
describe('update()', () => {
it('영화 수정 해줘', () => {
service.create({
title: 'testMovie',
year: 2022,
genres: ['액션', '코미디'],
});
service.update(1, { title: 'updateTestMovie' });
const movie = service.getOne(1);
expect(movie.title).toEqual('updateTestMovie');
});
});
});
});
404 에러 메세지 테스팅에서 생긴 일
- 404에러를 테스팅 하던 중 만난 에러
- 999뒤에 공백이 하나 있었다. (코드 작성하다가 실수로 넣은 공백)
- 중요한 테스트는 아니었지만, 예상치 못하게 테스트 코드 작성의 순 기능을 알게 됐다. (사소한 실수로 인한 에러(오타같은 것)를 미리 잡아 낼 수 있었다.)
모든 유닛 테스트를 마친 후 커버리지
E2E 테스트
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => {
let app: INestApplication;
// beforeEach 테스트 마다 연결을 해준다. 즉 테스트 함수들이 실행 될 때 마다 실행 된다.
// beforeAll() -> 테스트 함수마다 매번 연결을 맺고 끊는 것이 아닌 맨 처음에 한번 연결을 하고
// 여러 함수 테스트에 걸쳐서 사용한 후 마지막에 연결을 끊는다.
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
// main.ts 에서 사용한 transform이 테스트 서버에선 작동 하지 않는다.
// 즉 id값이 string으로 동작하게 되므로 getOne() 함수의 테스트가 이뤄지지 않는다.
// 그렇기 때문에 테스트 app 안에서도 ValidationPipe를 작성해주면서
// 실제 앱과 같은 환경으로 설정해준다.
app = moduleFixture.createNestApplication();
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Welcome to my Movie API');
});
describe('/movies', () => {
it('GET', () => {
return request(app.getHttpServer()).get('/movies').expect(200).expect([]);
});
it('POST 201', () => {
return request(app.getHttpServer())
.post('/movies')
.send({
title: 'Test',
year: 2000,
genres: ['test'],
})
.expect(201);
});
it('POST 400', () => {
return request(app.getHttpServer())
.post('/movies')
.send({
title: 'Test',
year: 2000,
genres: ['test'],
other: 'thing',
})
.expect(400);
});
it('DELETE', () => {
return request(app.getHttpServer()).delete('/movies').expect(404);
});
});
describe('/movies/:id', () => {
it('GET 200', () => {
return request(app.getHttpServer()).get('/movies/1').expect(200);
});
it('GET 404', () => {
return request(app.getHttpServer()).get('/movies/999').expect(404);
});
it('PATCH 200', () => {
return request(app.getHttpServer())
.patch('/movies/1')
.send({ title: 'updateTitle' })
.expect(200);
});
it('DELETE', () => {
return request(app.getHttpServer()).delete('/movies/1').expect(200);
});
});
});
'Nest.js' 카테고리의 다른 글
[Nest.js] Nest.js + PostgreSQL + typeORM CRUD 구현하기 1 (1) | 2023.01.26 |
---|---|
[Nest.js] Providers란? (0) | 2023.01.25 |
[Nest.js] DTO, 모듈화, ValidationPipe 실습 (0) | 2023.01.12 |
[Nest.js] Nest.js CRUD 실습 (REST API) (0) | 2023.01.11 |
[Nest.js] Nest 설치 (0) | 2023.01.11 |