PreferService Jest (1)

이건선·2023년 5월 16일
0

해결

목록 보기
36/48
post-custom-banner

사용할 예제 Service

...

@Injectable()
export class PreferService {
  constructor(
    @InjectRepository(Prefers)
    private prefersRepository: Repository<Prefers>,
    @InjectRepository(CardPosts)
    private cardPostsRepository: Repository<CardPosts>,
  ) {}

  /**
   * 1. 상세 페이지 투표결과 보기
   * @param postIdx
   * @returns
   */
  async postPollResult(postIdx: UUID): Promise<object> {
    const exeistPost = await this.cardPostsRepository.findOne({
      where: { postIdx },
    });

    if (!exeistPost) {
      throw new BadRequestException('해당 포스트가 존재하지 않습니다.');
    }

    const qb: SelectQueryBuilder<Prefers> = await this.prefersRepository
      .createQueryBuilder('p')
      .where('p.postIdx = :postIdx', { postIdx })
      .select([
        'COUNT(CASE WHEN p.selectprefer = 7 THEN 1 END) as proCount',
        'COUNT(CASE WHEN p.selectprefer = 8 THEN 1 END) as conCount',
      ]);

    return qb.getRawOne();
  }

...

postPollResult 메서드에서 시도해 볼 만한 유닛테스트 두 가지를 연습해보자.

  1. if (!exeistPost) 해당 포스트가 존재하지 않았을 때 에러 테스트
  2. return qb.getRawOne(); 성공적으로 포스트를 가져왔을 경우 테스트

Service.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { PreferService } from './prefer.service';
import { Repository } from 'typeorm';
import { getRepositoryToken } from '@nestjs/typeorm';
import { CardPosts } from 'src/entities/CardPosts.entity';
import { BadRequestException } from '@nestjs/common';

const mockPreferEntity = () => ({
  findOne: jest.fn(),
});

type MockRepository<T = any> = Partial<Record<keyof Repository<T>, jest.Mock>>;
describe('PreferService', () => {
  let preferService: PreferService;
  let cardPostsRepository: MockRepository<CardPosts>;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        PreferService,
        {
          provide: getRepositoryToken(CardPosts),
          useValue: mockPreferEntity(),
        },
      ],
    }).compile();

    cardPostsRepository = module.get<MockRepository<CardPosts>>(
      getRepositoryToken(CardPosts),
    );
    preferService = module.get<PreferService>(PreferService);
  });

  it('should be defined', () => {
    expect(preferService).toBeDefined();
  });

위와 같이 의존성 관련한 세팅을 끝내고 아래의 두가지 경우를 테스트 해보았다.




테스트를 좀 더 구체화 해서 생각해보기

  • if (!exeistPost) 해당 포스트가 존재하지 않았을 때 에러 테스트

    1. 테스트 조건이 해당포스트가 존재하지 않아야 하기 때문에 findOne메서드가 호출되면 null을 반환 한다.

      jest.spyOn(cardPostsRepository, 'findOne').mockResolvedValue(null);
    2. 그러므로 expect 의 값은 null이 될 것이고 rejects를 반환할 것이며 에러를 던진다 에러는 BadRequestException

      await expect(preferService.postPollResult(postIdx)).rejects.toThrow(
              BadRequestException,
  • return qb.getRawOne(); 성공적으로 포스트를 가져왔을 경우 테스트

    1. 우선 findOne 메서드의 반환 값이 존재해야 if문을 통과 할 수 있으므로 findOne 메서드를 호출했을 때 임시로 postIdx를 반환하게 한다.

      jest.spyOn(cardPostsRepository, 'findOne').mockResolvedValue({
              postIdx,
            } as any);
    2. 그리고 if문을 통과하고 createQueryBuilder 를 호출 하게 되면 실제 데이터베이스 쿼리를 생성하고 실행하는 대신, 우리가 원하는 동작을 하는 가짜 QueryBuilder를 반환한다.

    	jest
        .spyOn(prefersRepository, 'createQueryBuilder')
        .mockImplementationOnce(() => {
          const qb: any = {
            where: jest.fn().mockReturnThis(),
            select: jest.fn().mockReturnThis(),
            getRawOne: jest.fn().mockResolvedValue(expectedResult),
          };
          return qb;
        });
  1. where: jest.fn().mockReturnThis()와 같은 코드는 Jest의 mock 함수를 생성하고, 이 함수가 호출될 때마다 this를 반환하도록 설정하는 것.
  2. 마지막으로, getRawOne: jest.fn().mockResolvedValue(expectedResult)getRawOne 메서드가 호출되면 expectedResult를 반환하도록 설정한다.

postPollResult 메서드 테스트코드

describe('postPollResult', () => {
    it('post가 존재하지 않는 에러', async () => {
      const postIdx = 'fd05b208-12c3-4b6c-bd8e-eea8e5e202c9';
      jest.spyOn(cardPostsRepository, 'findOne').mockResolvedValue(null);

      await expect(preferService.postPollResult(postIdx)).rejects.toThrow(
        BadRequestException,
      );
    });

    it('성공적인 포스트 가져오기', async () => {
      const postIdx = 'fd05b208-12c3-4b6c-bd8e-eea8e5e202c9';
      const expectedResult = { proCount: 5, conCount: 3 };

      jest.spyOn(cardPostsRepository, 'findOne').mockResolvedValue({
        postIdx,
      } as any);
      jest
        .spyOn(prefersRepository, 'createQueryBuilder')
        .mockImplementationOnce(() => {
          const qb: any = {
            where: jest.fn().mockReturnThis(),
            select: jest.fn().mockReturnThis(),
            getRawOne: jest.fn().mockResolvedValue(expectedResult),
          };
          return qb;
        });

      const result = await preferService.postPollResult(postIdx);
      expect(result).toEqual(expectedResult);
    });
  });

resultexpectedResult와 일치하는지 확인한다. 일치하면 테스트가 통과하고, 그렇지 않으면 실패한다.

profile
멋지게 기록하자
post-custom-banner

0개의 댓글