[Nest.JS] 테스트 코드 작성하기

JUNHO YEOM·2022년 11월 15일
0

Nest.JS

목록 보기
7/7
post-thumbnail

테스트 코드 작성하기

import { NotFoundException } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { ErrorType } from '../../../common/type/Message.type';
import { Repository } from 'typeorm';
import { User } from '../entities/user.entity';
import { UserService } from '../user.service';

type MockRepository<T = any> = Partial<Record<keyof Repository<T>, jest.Mock>>;

const user = {
  email: 'jhyeom1545@gmail.com',
  name: '홍길동',
  points: 500,
  password: '12345',
  createdAt: new Date('2022-10-11T18:47:32.165Z'),
  updatedAt: new Date('2022-10-11T18:47:32.165Z'),
  deletedAt: null,
};

const mockRepository = () => ({
  save: jest.fn(),
  findOne: jest.fn(),
  softDelete: jest.fn(),
});

describe('UserService', () => {
  let userService: UserService;
  let userRepository: MockRepository<User>;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        UserService,
        {
          provide: 'UserRepository',
          useFactory: mockRepository,
        },
      ],
    }).compile();

    userService = module.get<UserService>(UserService);
    userRepository = module.get('UserRepository') as MockRepository<User>;
  });

  it('유저 서비스 toBeDefined 테스트', () => {
    expect(userService).toBeDefined(); 
  });

  describe('findOne', () => {
    it('유효한 email일 경우 user를 반환합니다.', async () => {
      jest.spyOn(userRepository, 'findOne').mockResolvedValue(user);
      const validUser = 'jhyeom1545@gmail.com';
      const result = await userService.findOne({ email: validUser });
      expect(result).toEqual(user);
    });
    it('유효하지 않은 email일 경우 예외를 발생시킵니다.', async () => {
      jest.spyOn(userRepository, 'findOne').mockResolvedValue(undefined);
      await expect(async () => {
        await userService.findOne({ email: 'isnotValid@naver.com' });
      }).rejects.toThrowError(new NotFoundException(ErrorType.user.msg));
    });
  });
});

유저 서비스의 findOne부분만을 작성한 테스트 코드는 다음과 같습니다.


MockRepository 사용하기

type MockRepository<T = any> = Partial<Record<keyof Repository<T>, jest.Mock>>;

keyof Repository로 해당 레포지토리가 가지고 있는 메서드를 추출한 다음, Partial로 감싸 optional 처리를 진행해줍니다.

Partial Type, Pick Type, Omit Type

Partial Type: 파셜 타입은 특정 타입의 부분 집합을 만족하는 타입을 정의할 수 있습니다.
Pick Type: 픽 타입은 특정 타입에서 몇 개의 속성을 선택하여 타입을 정의합니다.
Omit Type: 특정 속성만 제거한 타입을 정의합니다. pick의 반대

typeof : 객체 데이터를 객체 타입으로 변환해주는 연산자


User.service.ts

async findOne({ email }: { email: string }): Promise<User> {
    const result = await this.userRepository.findOne({
      where: { email },
    });
    // 이메일 존재하는지 확인
    if (!result) throw new NotFoundException(ErrorType.user.msg);
    return result;
  }

User.service.ts 코드의 findOne은 찾는 결과가 없을 경우 NotFountException을 발생시킵니다.


users.service.spec.ts

describe('findOne', () => {
    it('유효한 email일 경우 user를 반환합니다.', async () => {
      jest.spyOn(userRepository, 'findOne').mockResolvedValue(user);
      const validUser = 'jhyeom1545@gmail.com';
      const result = await userService.findOne({ email: validUser });
      expect(result).toEqual(user);
    });
    it('유효하지 않은 email일 경우 예외를 발생시킵니다.', async () => {
      jest.spyOn(userRepository, 'findOne').mockResolvedValue(undefined);
      await expect(async () => {
        await userService.findOne({ email: 'isnotValid@naver.com' });
      }).rejects.toThrowError(new NotFoundException(ErrorType.user.msg));
    });
  });

테스트코드는 다음과 같이 작성하였습니다.


userService.findOne 유효한 이메일일 경우

    it('유효한 email일 경우 user를 반환합니다.', async () => {
      jest.spyOn(userRepository, 'findOne').mockResolvedValue(user);
      const validUser = 'jhyeom1545@gmail.com';
      const result = await userService.findOne({ email: validUser });
      expect(result).toEqual(user);
    });

앞선 전체 코드에서 mockRepository의 findOne을 jest.fn()으로 바꿔 주었습니다.
그리고 mockResolvedValue를 통해서 await userRepository.findOne의 값이 user를 가지도록 만들어 주었습니다.
이렇게 작성하였을 경우, userService.findOne을 실행했을 때, user를 반환합니다.
jhyeom1545@gmail.com의 값은 존재하는 값이기 때문에 user를 반환하고 테스트가 성공합니다.


유효하지 않은 email일 경우

it('유효하지 않은 email일 경우 예외를 발생시킵니다.', async () => {
      jest.spyOn(userRepository, 'findOne').mockResolvedValue(undefined);
      await expect(async () => {
        await userService.findOne({ email: 'isnotValid@naver.com' });
      }).rejects.toThrowError(new NotFoundException(ErrorType.user.msg));
    });
// ErrorType.user.msg === 유효하지 않은 이메일입니다.

userRepository.findOne의 값이 undefined의 값을 갖도록 mockValue를 넣어 주었다.
User.service.findOne의 result가 존재하지 않을 경우 NotFoundException이 발생 하기 때문에,
expect를 통해 userService.findOne의 예상 결과가 NotFoundException('유효하지 않은 이메일입니다.')을 반환할 것임을 알 수 있습니다.
rejects는 Promise에 Error가 발생할 경우 사용됩니다.

0개의 댓글