...
@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 메서드에서 시도해 볼 만한 유닛테스트 두 가지를 연습해보자.
if (!exeistPost)
해당 포스트가 존재하지 않았을 때 에러 테스트return qb.getRawOne();
성공적으로 포스트를 가져왔을 경우 테스트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)
해당 포스트가 존재하지 않았을 때 에러 테스트
테스트 조건이 해당포스트가 존재하지 않아야 하기 때문에 findOne메서드가 호출되면 null을 반환 한다.
jest.spyOn(cardPostsRepository, 'findOne').mockResolvedValue(null);
그러므로 expect
의 값은 null이 될 것이고 rejects를 반환할 것이며 에러를 던진다 에러는 BadRequestException
await expect(preferService.postPollResult(postIdx)).rejects.toThrow(
BadRequestException,
return qb.getRawOne();
성공적으로 포스트를 가져왔을 경우 테스트
우선 findOne
메서드의 반환 값이 존재해야 if문을 통과 할 수 있으므로 findOne
메서드를 호출했을 때 임시로 postIdx를 반환하게 한다.
jest.spyOn(cardPostsRepository, 'findOne').mockResolvedValue({
postIdx,
} as any);
그리고 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;
});
where: jest.fn().mockReturnThis()
와 같은 코드는 Jest의 mock 함수를 생성하고, 이 함수가 호출될 때마다 this를 반환하도록 설정하는 것. getRawOne: jest.fn().mockResolvedValue(expectedResult)
는 getRawOne
메서드가 호출되면 expectedResult
를 반환하도록 설정한다.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);
});
});
result
가 expectedResult
와 일치하는지 확인한다. 일치하면 테스트가 통과하고, 그렇지 않으면 실패한다.