2025년 2월 5일

김동환·2025년 2월 5일

TIL (Today I Learned) - NestJS 댓글 컨트롤러 유닛 테스트

NestJS에서 CommentsController 유닛 테스트 작성

오늘은 NestJS의 댓글 컨트롤러(CommentsController)에 대한 유닛 테스트를 작성하는 방법을 학습했다.
NestJS에서 컨트롤러의 동작을 검증하기 위해 @nestjs/testing 패키지를 활용하여 테스트 모듈을 생성하고,
가짜(Mock) 서비스 객체를 주입하는 방식으로 테스트를 진행했다.


🔹 1. 테스트를 위한 기본 설정

describe 블록과 beforeEach 설정

  • describe를 사용하여 "댓글 컨트롤러(CommentsController)"에 대한 테스트 블록을 만들었다.
  • beforeEach에서 Test.createTestingModule()을 사용하여 테스트 모듈을 설정하고,
    • CommentsController를 컨트롤러로 등록하고,
    • CommentsService가짜(mock) 객체useValue로 주입했다.
  • JwtAuthGuard를 우회하기 위해 overrideGuard(JwtAuthGuard).useValue({ canActivate: () => true })를 사용하여 인증을 무시했다.

🔹 2. 컨트롤러 기본 정의 테스트

it('컨트롤러가 정의되어 있어야 한다.', () => {
  expect(controller).toBeDefined();
});
  • 컨트롤러가 정상적으로 생성되었는지 확인하는 기본 테스트이다.

🔹 3. 댓글 생성 API 테스트

describe('댓글 생성', () => {
  it('새로운 댓글을 생성해야 한다.', async () => {
    const dto: CreateCommentDto = { content: '새 댓글' };
    const result = { id: 1, cardId: 1, userId: 1, content: '새 댓글' };

    mockCommentsService.createComment.mockResolvedValue(result);

    expect(await controller.createComment({ user: { id: 1 } }, 1, dto)).toEqual({ data: result });

    expect(service.createComment).toHaveBeenCalledWith(1, 1, '새 댓글');
  });
});
  • 댓글 생성 API(/comments)의 동작을 검증하는 테스트이다.
  • mockCommentsService.createComment가 정상적으로 호출되고, 예상된 값이 반환되는지 확인했다.

🔹 4. 특정 카드의 댓글 목록 조회 API 테스트

describe('카드별 댓글 조회', () => {
  it('카드에 달린 모든 댓글을 반환해야 한다.', async () => {
    const result = [{ id: 1, cardId: 1, content: '테스트 댓글' }];

    mockCommentsService.getCommentByCardId.mockResolvedValue(result);

    expect(await controller.findAllComment(1)).toEqual({ data: result });

    expect(service.getCommentByCardId).toHaveBeenCalledWith(1);
  });
});
  • 특정 카드에 달린 모든 댓글을 가져오는 API(/comments/card/:cardId)를 테스트했다.
  • getCommentByCardId가 올바르게 호출되었는지 검증했다.

🔹 5. 특정 ID의 댓글 조회 API 테스트

describe('댓글 단건 조회', () => {
  it('특정 ID의 댓글을 반환해야 한다.', async () => {
    const result = { id: 1, cardId: 1, content: '테스트 댓글' };

    mockCommentsService.getCommentById.mockResolvedValue(result);

    expect(await controller.findOneComment(1)).toEqual(result);

    expect(service.getCommentById).toHaveBeenCalledWith(1);
  });
});
  • 특정 ID의 댓글을 조회하는 API(/comments/:id)의 동작을 검증했다.

🔹 6. 댓글 수정 API 테스트

describe('댓글 수정', () => {
  it('댓글을 수정해야 한다.', async () => {
    const dto: UpdateCommentDto = { content: '수정된 댓글' };
    const result = { id: 1, userId: 1, content: '수정된 댓글' };

    mockCommentsService.updateComment.mockResolvedValue(result);

    expect(await controller.updateComment({ user: { id: 1 } }, 1, dto)).toEqual({ data: result });

    expect(service.updateComment).toHaveBeenCalledWith(1, 1, '수정된 댓글');
  });
});
  • 댓글 수정 API(/comments/:id)의 동작을 검증했다.
  • updateComment가 올바른 인자로 호출되는지 확인했다.

🔹 7. 댓글 삭제 API 테스트

describe('댓글 삭제', () => {
  it('댓글을 삭제해야 한다.', async () => {
    const result = { id: 1, userId: 1, deleted: true };

    mockCommentsService.deleteComment.mockResolvedValue(result);

    expect(await controller.deleteComment({ user: { id: 1 } }, 1)).toEqual({ data: result });

    expect(service.deleteComment).toHaveBeenCalledWith(1, 1);
  });
});
  • 댓글 삭제 API(/comments/:id)의 동작을 검증했다.
  • deleteComment가 예상대로 호출되었는지 확인했다.

배운 점

  1. NestJS의 @nestjs/testing을 사용하여 테스트 모듈을 구성하는 방법을 익혔다.
  2. 서비스(Mock Service)를 주입하여 컨트롤러의 유닛 테스트를 작성하는 방법을 학습했다.
  3. jest.fn()을 사용하여 Mock 객체의 동작을 설정하는 방법을 배웠다.
  4. 각 API의 요청 및 응답을 검증하는 테스트 코드 작성 방법을 연습했다.
  5. overrideGuard(JwtAuthGuard)를 사용하여 인증을 우회하는 방법을 활용했다.

느낀 점

NestJS에서 컨트롤러 테스트를 작성하면서 jest@nestjs/testing을 활용한 Mock 객체 생성 및 주입이 핵심이라는 점을 깨달았다.
또한 beforeEach를 사용해 반복적인 설정을 줄일 수 있었고, 개별 API 테스트에서 서비스 메서드가 올바르게 호출되는지 확인하는 과정이 중요하다는 것도 배웠다.

다음에는 E2E 테스트도 함께 진행하여 API의 전체적인 동작을 검증하는 방법을 연습해보고 싶다!

profile
Node.js 7기

0개의 댓글