작성한 코드가 제대로 동작하는지 확인하기 위해 작성하는 코드를 테스트 코드
라고 한다.
업데이트 배포 과정에서 어떤 기능을 추가하였는데, 기존에 잘 동작하던 기능들이 잘 동작하지 않는 경우가 발생할 수 있다. 업데이트 배포 과정에서 이런 경우를 방지하려면 기존의 기능들과 새롭게 추가하려는 기능들까지 모두 처음부터 다시 테스트해야 한다.
하지만 배포를 할 때마다 모든 기능이 의도대로 잘 동작하는지를 확인하는 것은 어렵고 비효율적이다. 이런 경우 배포하기 전에 테스트 코드를 작성하여 기능을 추가할 때마다 기능 테스트를 진행하여 기능이 정상 동작하는지를 확인하는 것이 좋다.
결국 어떤 API 기능을 구현했다면 반드시 테스트 코드를 작성하여 기능이 정상 동작하는지를 확인해야 한다.
unit test - 단위 테스트
integration test - 통합 테스트
e2e(end-to-end) test - 엔드투엔드 테스트
Jest는 페이스북에서 개발한, 자바스크립트 코드의 정확성을 테스트할 수 있도록 테스트 코드 작성을 도와주는
자바스크립트 테스트 프레임워크
이다.
여러 테스트 라이브러리들을 조합하지 않고 편리하게 코드를 테스트할 수 있다.
NestJS 프로젝트를 생성하면 기본적으로 spec
이라는 이름이 들어간 파일을 Jest의 테스트 파일로 읽는다. (testRegex
확인)
app.controller.spec.ts
파일의 기본 구조는 아래와 같다.
describe
- 여러 테스트를 모아 놓은 그룹 단위beforeEach
- test(it) 이전에 실행되는 부분으로 각각의 test(it)를 실행하기 전에 매번 실행하고 초기화를 반복한다.test(it)
- 하나의 테스트 단위파일의 기본 구조에서 beforeAll
도 존재하는데, beforeAll
은 모든 test(it)를 실행하기 전에 딱 한번만 실행된다.
NestJS 프로젝트에서 app.controller.ts의 기본 API에 대한 테스트 코드를 작성해서 테스팅하는 방법에 대해 알아보자.
기본 app.service.ts와 app.controller.ts 파일은 아래와 같다.
// app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
// app.controller.ts
import { Controller, Get, Post } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(
private readonly appService: AppService, // AppService 의존성 주입
) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
Jest로 테스트 코드를 작성하기 위해 spec
파일을 생성하고 아래와 같이 코드를 작성한다.
// aaa2.spec.ts
import { AppController } from './app.controller';
import { AppService } from './app.service';
describe('AppController', () => { // AppController 테스트 그룹
let appService: AppService;
let appController: AppController;
beforeEach(() => { // test 시작 전 초기화
appService = new AppService();
appController = new AppController(appService);
});
describe('getHello', () => {
it('이 테스트의 검증 결과는 Hello World를 리턴해야함!!!', () => { // 실제 테스트 실행
expect(appController.getHello()).toBe('Hello World!');
});
});
});
describe
에 테스트할 AppService
, AppController
를 위한 변수 선언beforeEach
에서 AppService
, AppController
인스턴스를 생성beforeEach
는 각 테스트 시작 전마다 실행된다.yarn test
명령어로 테스트 코드를 실행하여 API 기능 테스트를 진행한다.
PASS
문구를 통해 AppController
의 getHello()
API 기능이 잘 동작하는 것을 확인할 수 있다.NestJS에서 제공하는 @nestjs/testing
을 사용하면 테스트에 사용하는 종속성만 선언해서 모듈을 만들고 해당 모듈로 service
나 repository
를 가져올 수 있다. 위에서 살펴본 테스트 코드를 종속성을 선언해서 생성한 테스팅 모듈을 사용하는 방식으로 변경하면 아래와 같다.
// aaa3.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';
describe('AppController', () => { // AppController 테스트 그룹
let appController: AppController; // AppController를 가져오기 위한 변수
beforeEach(async () => {
// 테스트에 사용하는 의존성만 선언하여 테스팅 모듈 생성
const app: TestingModule = await Test.createTestingModule({
controllers: [AppController], // 1️⃣ AppController에
providers: [AppService], // 2️⃣ AppService 의존성 주입
}).compile();
appController = app.get<AppController>(AppController); // 테스팅 모듈을 통해 AppController 가져오기
});
describe('getHello', () => { // AppController의 getHello API 테스트 그룹
it('이 테스트의 검증 결과는 Hello World를 리턴해야함!!!', () => { // AppController의 getHello API 테스트 실행
expect(appController.getHello()).toBe('Hello World!');
});
});
});
beforeEach
에서 app
이라는 테스팅 모듈을 생성한다.controllers
와 providers
에 각각 AppController와 AppService를 넣는다..get<AppController>(AppController)
로 app
테스팅 모듈을 통해 AppController
를 가져온다.AppController
를 appController
변수에 할당해 테스팅 모듈에 연결한다.