반응형
Intro
Jest를 이용한 어노테이션이나 문법들 복습해봤으니 실제 API를 만들면서 CRUD를 TDD 해보려고 한다.
DB는 연결하지 않고 간단하게 controller - service의 관한 테스트 코드를 만들어보려고 한다.
BoardController 유닛테스트 세팅
레드 단계를 진행하기 전에 beforeEach를 통해서 BoardController를 TestingModule을 이용해서 세팅을 해줘야 한다.
import { Test, TestingModule } from '@nestjs/testing';
import { BoardController } from '../board.controller';
import { BoardService } from '../board.service';
describe('BoardController', () => {
let boardController: BoardController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [BoardController],
providers: [
{
provide: BoardService,
useValue: {},
},
],
}).compile();
boardController = module.get<BoardController>(BoardController);
});
});
- Test.createTestingModule
- '@nestjs/testing' 라이브러리를 통해서 Test 메서드를 사용할 수 있다
- 이 메서드를 사용하여 사용할 모듈을 생성할 수 있다
- BoardController 모듈을 사용해야 하기 때문에 여기서는 BoardController 생성을 해준다
- BoardController 안에서는 BoardService를 사용해야 하기 때문에 모듈을 생성할 때 같이 DI를 시켜준다
GET /board;
RED 단계
모든 케이스에 대해서 테스트 코드를 작성하지 않고, 성공 케이스에 대해서만 테스트 코드를 작성하려고 한다.
모든 board를 가져오는 API를 만들기 전에 테스트 코드를 먼저 작성한다(RED)
describe('GET /board', () => {
/* 성공 케이스 */
it('should return an array of boards', () => {
// given
const result = [
{
title: 'new board',
content: 'new board content',
},
];
// when
jest.spyOn(boardService, 'findAll').mockReturnValue(result);
// then
expect(boardController.findAll()).toEqual(result);
});
/* 실패 케이스 */
// 구현은 안 했지만 여기 이후부터 실패 혹은 예외 케이스를 구현해주면 된다
});
- 코드 내용을 보면 boardService.findAll() 메서드를 호출하여 board 리스트를 받아오는 코드이다
- 그리고 when 절에서 findAll을 mocking을 해주어 결과값을 result로 해주었다.
- 지금 이 테스트 코드는 백날 실행해봤자 무조건 실패하는 테스트 코드이면서 잘못된 테스트 코드이다.
- 실패 이유: 테스트 코드만 구현이 되어 있고, 실제 코드는 구현이 되어 있지 않다
- 잘못된 이유: 언뜻 보면 잘 작성된 테스트 코드처럼 보일 수 있지만, beforeEach에서 'findAll()' 메서드를 mocking을 해주어야 한다
beforeEach 수정
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [BoardController],
providers: [
{
provide: BoardService,
useValue: {
findAll: () => jest.fn().mockReturnValue([]),
},
},
],
}).compile();
boardController = module.get<BoardController>(BoardController);
});
- providers 부분에서 BoardService를 DI 시켜준 것을 확인할 수 있다
- 또한 주입을 시켜주면서 동시에 findAll() 메서드의 반환값을 mockReturnValue()를 이용해서 빈 배열을 반환하도록 mocking을 해준 것을 확인할 수 있다.
- 이렇든 useValue와 mockReturnValue를 통해서 한 메서드의 반환값을 mocking 해줄 수 있다
GREEN 단계
GREEN 단계를 위해 3가지를 수정해야 한다. boardController를 수정을 하게 되면 당연히 boardService 모듈 안에 메서드를 사용할텐데, 이 메서드는 아직 테스트 코드가 작성되어 있지 않다. 그래서 boardSerivce.spec에서 findAll이라는 메서드에 대해서 테스트 코드를 작성해주어야 하고, 또한 boardService의 실제 코드도 작성해주어야 한다.
- boardController
@Get()
findAll() {
return this.boardService.findAll();
}
- boardSerivce.spec
- boardService.spec도 boardController.spec과 마찬가지고 beforeEach를 통해서 테스트 세팅을 해주어야 한다
- 위에 설명이 되어 있기 때문에 과정은 생략한다
import { Test, TestingModule } from '@nestjs/testing';
import { BoardService } from '../board.service';
describe('BoardService', () => {
let boardService: BoardService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [BoardService],
}).compile();
boardService = module.get<BoardService>(BoardService);
});
describe('findAll', () => {
// 성공 케이스
it('should return boards', () => {
// given
const result = [
{
title: 'new board',
content: 'new board content',
},
];
// when
jest.spyOn(boardService, 'findAll').mockReturnValue(result);
// then
expect(boardService.findAll()).toEqual(result);
});
// 실패 케이스
// 실패 케이스는 나중에
});
});
- boardService
import { Injectable } from '@nestjs/common';
@Injectable()
export class BoardService {
boards = [];
findAll() {
return this.boards;
}
}
느낀점
상당히 오래 걸리고 힘들다.. 근데 할만하다
하면서 애매했던 메서드(mockReturnValue, mockImplementation 등)들이 있는데 그 부분을 좀 더 보완해야 될 것 같다
반응형
'TDD' 카테고리의 다른 글
| Jest 많이 썼던 내용들 정리 (1) (5) | 2024.10.24 |
|---|---|
| Jest; JUnit 어노테이션을 참고한 (0) | 2024.08.31 |
| 단위 테스트: 기본 개념 (0) | 2024.08.31 |
| 예제; 암호 검사기 (0) | 2024.08.31 |
| 테스트의 개념과 중요성 (0) | 2024.08.31 |