오늘은 NestJS의 댓글 컨트롤러(CommentsController)에 대한 유닛 테스트를 작성하는 방법을 학습했다.
NestJS에서 컨트롤러의 동작을 검증하기 위해 @nestjs/testing 패키지를 활용하여 테스트 모듈을 생성하고,
가짜(Mock) 서비스 객체를 주입하는 방식으로 테스트를 진행했다.
describe 블록과 beforeEach 설정describe를 사용하여 "댓글 컨트롤러(CommentsController)"에 대한 테스트 블록을 만들었다.beforeEach에서 Test.createTestingModule()을 사용하여 테스트 모듈을 설정하고,CommentsController를 컨트롤러로 등록하고,CommentsService의 가짜(mock) 객체를 useValue로 주입했다.JwtAuthGuard를 우회하기 위해 overrideGuard(JwtAuthGuard).useValue({ canActivate: () => true })를 사용하여 인증을 무시했다.it('컨트롤러가 정의되어 있어야 한다.', () => {
expect(controller).toBeDefined();
});
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, '새 댓글');
});
});
/comments)의 동작을 검증하는 테스트이다.mockCommentsService.createComment가 정상적으로 호출되고, 예상된 값이 반환되는지 확인했다.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);
});
});
/comments/card/:cardId)를 테스트했다.getCommentByCardId가 올바르게 호출되었는지 검증했다.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);
});
});
/comments/:id)의 동작을 검증했다.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, '수정된 댓글');
});
});
/comments/:id)의 동작을 검증했다.updateComment가 올바른 인자로 호출되는지 확인했다.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);
});
});
/comments/:id)의 동작을 검증했다.deleteComment가 예상대로 호출되었는지 확인했다.@nestjs/testing을 사용하여 테스트 모듈을 구성하는 방법을 익혔다.jest.fn()을 사용하여 Mock 객체의 동작을 설정하는 방법을 배웠다.overrideGuard(JwtAuthGuard)를 사용하여 인증을 우회하는 방법을 활용했다.NestJS에서 컨트롤러 테스트를 작성하면서 jest와 @nestjs/testing을 활용한 Mock 객체 생성 및 주입이 핵심이라는 점을 깨달았다.
또한 beforeEach를 사용해 반복적인 설정을 줄일 수 있었고, 개별 API 테스트에서 서비스 메서드가 올바르게 호출되는지 확인하는 과정이 중요하다는 것도 배웠다.
다음에는 E2E 테스트도 함께 진행하여 API의 전체적인 동작을 검증하는 방법을 연습해보고 싶다!