본문 바로가기

TDD

간단한 게시판 만들면서 TDD 맛보기 (POST 요청)

반응형

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