상황 : updateData와 movieData에게 타입을 부여하기 위해 서비스와 콘트롤러에 DTO(데이터 전송 객체)
export class createMovieDto{
readonly title:string;
readonly year: number;
readonly genres:string[];}
이후 서비스와 컨트롤러 살짝 바꿔줌(요청)
근데 왜 DTO 씀? : 프로그래밍 코드를 더 간결하게 만들어주고 NESTJS에 들어오는 쿼리의 대한 유효성을 검증해줌.
파이프 만들기(main) : 유효성 검사용, 미들웨어
app.useGlobalPipes(
new ValidationPipe()
)
추가 후
npm i class-validator, class-transformer 설치
import { IsNumber, IsString } from "class-validator";
export class CreateMovieDto{
@IsString()
readonly title:string;
@IsNumber()
readonly year: number;
@IsString({each : true})
readonly genres:string[];}
app.useGlobalPipes(
new ValidationPipe({
whitelist:true,
forbidNonWhitelisted:true
})
)
타입을 받을 때 스트링을 넘버로 바꿔준 사례, express에서는 일일이 다 해줘야 함
npm i @nestjs/mapped-types 설치 후
dto/update-movie.dto.ts
import { IsNumber, IsString } from "class-validator";
import {PartialType} from "@nestjs/mapped-types";
import {CreateMovieDto} from './create-movie.dto';
export class UpdateMovieDto extends PartialType(CreateMovieDto){
}
@IsOptional()
@IsString({each : true})
readonly genres:string[];}
DTO : 유효성 뿐 만 아니라 타입 변경도 가능하다!
선행작업
nest g mo
이름은 movies
이후 app.module 내용 일부 지우고 movie.module 수정
import { Module } from '@nestjs/common';
import { MoviesController } from './movies.controller';
import { MoviesService } from './movies.service';
@Module({
controllers:[MoviesController],
providers : [MoviesService]
})
export class MoviesModule {}
nest g co
이름 : app
추가 후 controller만 movie에 가져 옴(나머지는 삭제)
앱모듈 상태
@Module({
imports: [MoviesModule],
controllers: [AppController],
providers: [],
})
(짜여진 앱)
import { Controller, Get } from '@nestjs/common';
@Controller('')
export class AppController {
@Get()
home(){
return 'Welcome!'
}
}
이 상태로 locall3000 들어가면 나옴
익스프레스에서 쓰던 것 자주 쓰면 좋지 않음
npm run test:cov 하고 진행
npm run test:watch 하고 진행하면 테스트 파일을 볼 수 있음
서비스에서 분리된 유닛을 테스트하는 것 vs 모든 시스템 테스트
unit : getOne하나만
e2e : 유저 관점에서 취할만 한 전체
describe("getAll()", () => {
it ("should be return an array", ()=>{
const result = service.getAll();
expect(result).toBeInstanceOf(Array)
})
})
describe("getOne", () => {
it ("should return a movie", () =>{
service.create({
title : "Test Movie",
genres : ["Test"],
year : 2000,
});
const movie = service.getOne(1);
expect(movie).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`);
}
})
});
(여러 에러 및 예외사항 처리해본 결과)
const beforeDelete = service.getAll().length;
service.deleteOne(1);
const afterDelete = service.getAll().length;
expect(afterDelete).toBeLessThan(beforeDelete);
});
it("should return a 404 error", ()=> {
try{
service.deleteOne(999);
}catch(e){
expect(e).toBeInstanceOf(NotFoundException);
}
})
})
it ("should create a movie", () => {
const beforeCreate = service.getAll().length
service.create({
title : "Test Movie",
genres : ["Test"],
year : 2000,
});
const afterCreate = service.getAll().length
expect(afterCreate).toBeGreaterThan(beforeCreate);
})
})
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, {});
}catch(e){
expect(e).toBeInstanceOf(NotFoundException);
}
});