Skip to content

Commit 651add9

Browse files
committed
modify: 리뷰 기반 테스트 코드 수정
1 parent ce5f111 commit 651add9

File tree

2 files changed

+85
-130
lines changed

2 files changed

+85
-130
lines changed

src/repositories/__test__/leaderboard.repo.test.ts

Lines changed: 64 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ import { LeaderboardRepository } from '@/repositories/leaderboard.repository';
44

55
jest.mock('pg');
66

7+
// pg의 QueryResult 타입을 만족하는 mock 객체를 생성하기 위한 헬퍼 함수 생성
8+
function createMockQueryResult<T extends Record<string, unknown>>(rows: T[]): QueryResult<T> {
9+
return {
10+
rows,
11+
rowCount: rows.length,
12+
command: '',
13+
oid: 0,
14+
fields: [],
15+
} satisfies QueryResult<T>;
16+
}
17+
718
const mockPool: {
819
query: jest.Mock<Promise<QueryResult<Record<string, unknown>>>, unknown[]>;
920
} = {
@@ -18,7 +29,7 @@ describe('LeaderboardRepository', () => {
1829
});
1930

2031
describe('getUserLeaderboard', () => {
21-
it('사용자 리더보드를 조회할 수 있어야 한다', async () => {
32+
it('사용자 통계 배열로 이루어진 리더보드를 반환해야 한다', async () => {
2233
const mockResult = [
2334
{
2435
id: 1,
@@ -41,142 +52,71 @@ describe('LeaderboardRepository', () => {
4152
post_diff: 1,
4253
},
4354
];
44-
45-
mockPool.query.mockResolvedValue({
46-
rows: mockResult,
47-
rowCount: mockResult.length,
48-
} as unknown as QueryResult);
55+
mockPool.query.mockResolvedValue(createMockQueryResult(mockResult));
4956

5057
const result = await repo.getUserLeaderboard('viewCount', 30, 10);
5158

5259
expect(mockPool.query).toHaveBeenCalledWith(expect.stringContaining('FROM users_user u'), expect.anything());
5360
expect(result).toEqual(mockResult);
5461
});
5562

56-
it('sort가 조회수인 경우 정렬 순서를 보장해야 한다.', async () => {
57-
const mockResult = [
58-
{ view_diff: 20, like_diff: 5, post_diff: 1 },
59-
{ view_diff: 10, like_diff: 10, post_diff: 2 },
60-
];
61-
62-
mockPool.query.mockResolvedValue({
63-
rows: mockResult,
64-
rowCount: mockResult.length,
65-
} as unknown as QueryResult);
66-
67-
const result = await repo.getUserLeaderboard('viewCount', 30, 10);
63+
it('sort가 viewCount인 경우 view_diff 필드를 기준으로 내림차순 정렬해야 한다', async () => {
64+
await repo.getUserLeaderboard('viewCount', 30, 10);
6865

69-
expect(result).toEqual(mockResult);
70-
expect(result[0].view_diff).toBeGreaterThan(result[1].view_diff);
66+
expect(mockPool.query).toHaveBeenCalledWith(
67+
expect.stringContaining('ORDER BY view_diff DESC'),
68+
expect.anything(),
69+
);
7170
});
7271

73-
it('sort가 좋아요 수인 경우 정렬 순서를 보장해야 한다.', async () => {
74-
const mockResult = [
75-
{ view_diff: 10, like_diff: 10, post_diff: 1 },
76-
{ view_diff: 20, like_diff: 5, post_diff: 1 },
77-
];
78-
79-
mockPool.query.mockResolvedValue({
80-
rows: mockResult,
81-
rowCount: mockResult.length,
82-
} as unknown as QueryResult);
72+
it('sort가 likeCount인 경우 like_diff 필드를 기준으로 내림차순 정렬해야 한다', async () => {
73+
await repo.getUserLeaderboard('likeCount', 30, 10);
8374

84-
const result = await repo.getUserLeaderboard('likeCount', 30, 10);
85-
86-
expect(result).toEqual(mockResult);
87-
expect(result[0].like_diff).toBeGreaterThan(result[1].like_diff);
75+
expect(mockPool.query).toHaveBeenCalledWith(
76+
expect.stringContaining('ORDER BY like_diff DESC'),
77+
expect.anything(),
78+
);
8879
});
8980

90-
it('sort가 게시물 수인 경우 정렬 순서를 보장해야 한다.', async () => {
91-
const mockResult = [
92-
{ view_diff: 10, like_diff: 10, post_diff: 4 },
93-
{ view_diff: 20, like_diff: 5, post_diff: 1 },
94-
];
95-
96-
mockPool.query.mockResolvedValue({
97-
rows: mockResult,
98-
rowCount: mockResult.length,
99-
} as unknown as QueryResult);
81+
it('sort가 postCount인 경우 post_diff 필드를 기준으로 내림차순 정렬해야 한다', async () => {
82+
await repo.getUserLeaderboard('postCount', 30, 10);
10083

101-
const result = await repo.getUserLeaderboard('postCount', 30, 10);
102-
103-
expect(result).toEqual(mockResult);
104-
expect(result[0].post_diff).toBeGreaterThan(result[1].post_diff);
84+
expect(mockPool.query).toHaveBeenCalledWith(
85+
expect.stringContaining('ORDER BY post_diff DESC'),
86+
expect.anything(),
87+
);
10588
});
10689

107-
it('limit 만큼의 데이터만 반환해야 한다', async () => {
108-
const mockData = [
109-
{ id: 1, title: 'test' },
110-
{ id: 2, title: 'test2' },
111-
{ id: 3, title: 'test3' },
112-
{ id: 4, title: 'test4' },
113-
{ id: 5, title: 'test5' },
114-
];
90+
it('limit 파라미터가 쿼리에 올바르게 적용되어야 한다', async () => {
11591
const mockLimit = 5;
11692

117-
mockPool.query.mockResolvedValue({
118-
rows: mockData,
119-
rowCount: mockData.length,
120-
} as unknown as QueryResult);
121-
122-
const result = await repo.getUserLeaderboard('viewCount', 30, mockLimit);
123-
124-
expect(result).toEqual(mockData);
125-
expect(result.length).toEqual(mockLimit);
93+
await repo.getUserLeaderboard('viewCount', 30, mockLimit);
12694

12795
expect(mockPool.query).toHaveBeenCalledWith(
12896
expect.stringContaining('LIMIT $2'),
12997
expect.arrayContaining([30, mockLimit]),
13098
);
13199
});
132100

133-
it('GROUP BY 절이 포함되어야 한다', async () => {
134-
mockPool.query.mockResolvedValue({
135-
rows: [],
136-
rowCount: 0,
137-
} as unknown as QueryResult);
138-
139-
await repo.getUserLeaderboard('viewCount', 30, 10);
140-
141-
expect(mockPool.query).toHaveBeenCalledWith(expect.stringContaining('GROUP BY u.id, u.email'), expect.anything());
142-
});
143-
144101
it('dateRange 파라미터가 쿼리에 올바르게 적용되어야 한다', async () => {
145-
const mockResult = [{ id: 1 }];
146-
const testDateRange = 30;
147-
148-
mockPool.query.mockResolvedValue({
149-
rows: mockResult,
150-
rowCount: mockResult.length,
151-
} as unknown as QueryResult);
102+
const mockDateRange = 30;
152103

153-
await repo.getUserLeaderboard('viewCount', testDateRange, 10);
104+
await repo.getUserLeaderboard('viewCount', mockDateRange, 10);
154105

155106
expect(mockPool.query).toHaveBeenCalledWith(
156-
expect.stringContaining('$1::int'),
157-
expect.arrayContaining([testDateRange, expect.anything()]),
107+
expect.stringContaining('make_interval(days := $1::int)'),
108+
expect.arrayContaining([mockDateRange, expect.anything()]),
158109
);
159110
});
160111

161-
it('데이터가 없는 경우 빈 배열을 반환해야 한다', async () => {
162-
mockPool.query.mockResolvedValue({
163-
rows: [],
164-
rowCount: 0,
165-
} as unknown as QueryResult);
166-
167-
const result = await repo.getUserLeaderboard('viewCount', 30, 10);
168-
169-
expect(result).toEqual([]);
170-
});
171-
172112
it('에러 발생 시 DBError를 던져야 한다', async () => {
173113
mockPool.query.mockRejectedValue(new Error('DB connection failed'));
174114
await expect(repo.getUserLeaderboard('viewCount', 30, 10)).rejects.toThrow(DBError);
175115
});
176116
});
177117

178118
describe('getPostLeaderboard', () => {
179-
it('게시물 리더보드를 조회할 수 있어야 한다', async () => {
119+
it('게시물 통계 배열로 이루어진 리더보드를 반환해야 한다', async () => {
180120
const mockResult = [
181121
{
182122
id: 2,
@@ -200,54 +140,52 @@ describe('LeaderboardRepository', () => {
200140
},
201141
];
202142

203-
mockPool.query.mockResolvedValue({
204-
rows: mockResult,
205-
rowCount: mockResult.length,
206-
} as unknown as QueryResult);
143+
mockPool.query.mockResolvedValue(createMockQueryResult(mockResult));
207144

208145
const result = await repo.getPostLeaderboard('viewCount', 30, 10);
209146

210147
expect(result).toEqual(mockResult);
211148
expect(mockPool.query).toHaveBeenCalledWith(expect.stringContaining('FROM posts_post p'), expect.anything());
212149
});
213150

214-
it('GROUP BY 절이 포함되지 않아야 한다', async () => {
215-
mockPool.query.mockResolvedValue({
216-
rows: [],
217-
rowCount: 0,
218-
} as unknown as QueryResult);
219-
151+
it('sort가 viewCount인 경우 view_diff 필드를 기준으로 내림차순 정렬해야 한다', async () => {
220152
await repo.getPostLeaderboard('viewCount', 30, 10);
221153

222-
expect(mockPool.query).toHaveBeenCalledWith(expect.not.stringContaining('GROUP BY'), expect.anything());
154+
expect(mockPool.query).toHaveBeenCalledWith(
155+
expect.stringContaining('ORDER BY view_diff DESC'),
156+
expect.anything(),
157+
);
223158
});
224159

225-
it('dateRange 파라미터가 쿼리에 올바르게 적용되어야 한다', async () => {
226-
const mockResult = [{ id: 1 }];
227-
const testDateRange = 30;
160+
it('sort가 likeCount인 경우 like_diff 필드를 기준으로 내림차순 정렬해야 한다', async () => {
161+
await repo.getPostLeaderboard('likeCount', 30, 10);
228162

229-
mockPool.query.mockResolvedValue({
230-
rows: mockResult,
231-
rowCount: mockResult.length,
232-
} as unknown as QueryResult);
163+
expect(mockPool.query).toHaveBeenCalledWith(
164+
expect.stringContaining('ORDER BY like_diff DESC'),
165+
expect.anything(),
166+
);
167+
});
168+
169+
it('limit 파라미터가 쿼리에 올바르게 적용되어야 한다', async () => {
170+
const mockLimit = 5;
233171

234-
await repo.getPostLeaderboard('viewCount', testDateRange, 10);
172+
await repo.getPostLeaderboard('viewCount', 30, mockLimit);
235173

236174
expect(mockPool.query).toHaveBeenCalledWith(
237-
expect.stringContaining('$1::int'),
238-
expect.arrayContaining([testDateRange, expect.anything()]),
175+
expect.stringContaining('LIMIT $2'),
176+
expect.arrayContaining([30, mockLimit]),
239177
);
240178
});
241179

242-
it('데이터가 없는 경우 빈 배열을 반환해야 한다', async () => {
243-
mockPool.query.mockResolvedValue({
244-
rows: [],
245-
rowCount: 0,
246-
} as unknown as QueryResult);
180+
it('dateRange 파라미터가 쿼리에 올바르게 적용되어야 한다', async () => {
181+
const mockDateRange = 30;
247182

248-
const result = await repo.getPostLeaderboard('viewCount', 30, 10);
183+
await repo.getPostLeaderboard('viewCount', mockDateRange, 10);
249184

250-
expect(result).toEqual([]);
185+
expect(mockPool.query).toHaveBeenCalledWith(
186+
expect.stringContaining('make_interval(days := $1::int)'),
187+
expect.arrayContaining([mockDateRange, expect.anything()]),
188+
);
251189
});
252190

253191
it('에러 발생 시 DBError를 던져야 한다', async () => {

src/services/__test__/leaderboard.service.test.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ describe('LeaderboardService', () => {
5050
];
5151

5252
const mockResult = {
53-
posts: null,
5453
users: [
5554
{
5655
id: 1,
@@ -76,20 +75,30 @@ describe('LeaderboardService', () => {
7675
};
7776

7877
repo.getUserLeaderboard.mockResolvedValue(mockRawResult);
79-
const result = await service.getUserLeaderboard();
78+
const result = await service.getUserLeaderboard('viewCount', 30, 10);
8079

8180
expect(result.users).toEqual(mockResult.users);
8281
});
8382

83+
it('쿼리 파라미터가 올바르게 적용되어야 한다', async () => {
84+
repo.getUserLeaderboard.mockResolvedValue([]);
85+
86+
await service.getUserLeaderboard('postCount', 30, 10);
87+
88+
expect(repo.getUserLeaderboard).toHaveBeenCalledWith('postCount', 30, 10);
89+
});
90+
8491
it('쿼리 파라미터가 입력되지 않은 경우 기본값으로 처리되어야 한다', async () => {
8592
repo.getUserLeaderboard.mockResolvedValue([]);
93+
8694
await service.getUserLeaderboard();
8795

8896
expect(repo.getUserLeaderboard).toHaveBeenCalledWith('viewCount', 30, 10);
8997
});
9098

9199
it('데이터가 없는 경우 빈 배열을 반환해야 한다', async () => {
92100
repo.getUserLeaderboard.mockResolvedValue([]);
101+
93102
const result = await service.getUserLeaderboard();
94103

95104
expect(result).toEqual({ users: [] });
@@ -153,17 +162,25 @@ describe('LeaderboardService', () => {
153162
releasedAt: '2025-01-02',
154163
},
155164
],
156-
users: null,
157165
};
158166

159167
repo.getPostLeaderboard.mockResolvedValue(mockRawResult);
160-
const result = await service.getPostLeaderboard();
168+
const result = await service.getPostLeaderboard('viewCount', 30, 10);
161169

162170
expect(result.posts).toEqual(mockResult.posts);
163171
});
164172

173+
it('쿼리 파라미터가 올바르게 적용되어야 한다', async () => {
174+
repo.getPostLeaderboard.mockResolvedValue([]);
175+
176+
await service.getPostLeaderboard('likeCount', 30, 10);
177+
178+
expect(repo.getPostLeaderboard).toHaveBeenCalledWith('likeCount', 30, 10);
179+
});
180+
165181
it('쿼리 파라미터가 입력되지 않은 경우 기본값으로 처리되어야 한다', async () => {
166182
repo.getPostLeaderboard.mockResolvedValue([]);
183+
167184
await service.getPostLeaderboard();
168185

169186
expect(repo.getPostLeaderboard).toHaveBeenCalledWith('viewCount', 30, 10);

0 commit comments

Comments
 (0)