
๐ฆ Mock์ด๋
Mock (๋ชจ์ ๊ฐ์ฒด)๋ ํ ์คํธ ํ๊ฒฝ์์
์ค์ ๊ฐ์ฒด์ ๋์์ ํ๋ด ๋ธ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ค.
์ด๋ ํ ์คํธ ๋์์ด ์๋ ์ธ๋ถ ์์กด์ฑ์ ์ ์ดํ๊ฑฐ๋ ๋์ฒดํจ์ผ๋ก์จ
ํ ์คํธ๋ฅผ ๋ ์ฝ๊ณ ์์ ์ ์ผ๋ก ์งํํ ์ ์๋๋ก ๋์์ค๋ค.
์๋ฅผ ๋ค๋ฉด, ์๋์ ๊ฐ์ ์ํฉ์์ Mock์ ์ฌ์ฉํ ์ ์๋ค.
1๏ธโฃ API ์์ฒญ์ ์ค์ ๋ก ๋ณด๋ด์ง ์๊ณ , ๋ฏธ๋ฆฌ ์ ํด๋ ์๋ต์ ํ๋ด๋ด๊ณ ์ถ์ ๋
// userService.ts
export const fetchUser = async () => {
const res = await fetch('/api/user');
return res.json();
};
fetchUser() ๋ผ๋ ํจ์๋ ์๋ฒ์ ์์ฒญํด์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐ์์ค๋ ํจ์์ธ๋ฐ,
ํ ์คํธ๋ฅผ ํ ๋๋ง๋ค ์ค์ ์๋ฒ์ ์์ฒญํจ๋ ๋๋ฆฌ๊ณ , ์๋ฒ๊ฐ ์์ผ๋ฉด ์๋ฌ๊ฐ ๋ ๊ฒ์ด๋ค.
๐๐ป ๋ฐ๋ผ์ fetch๋ฅผ ๊ฐ์ง(mock)๋ก ๋ฐ๊ฟ์น๊ธฐ ํด์ ๋ฏธ๋ฆฌ ์ ํด๋ ์๋ต์ ๋ณด๋ด๋๋ก ํด์ค์ผ ํ๋ค.
// userService.test.ts
import { fetchUser } from './userService';
global.fetch = vi.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ name: 'ssosso', age: 24 }),
})
) as jest.Mock;
test('fetchUser๊ฐ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํด์ผ ํ๋ค', async () => {
const user = await fetchUser();
expect(user.name).toBe('ssosso');
});
global.fetch = ... ๐๐ป ์ ์ญ์ ์๋ fetch ํจ์๋ฅผ ๋ฎ์ด์ฐ๊ธฐ ํด์ค๋ค.
์ด๋ ๊ฒ ํด์ฃผ๊ณ fetchUser()๋ฅผ ์คํํ๋ฉด,
์ฐ๋ฆฌ๊ฐ ์์์ mock์ผ๋ก ๋ง๋ ๊ฐ์ง ์๋ต์ด ๋์์ค๋๋ฐ,
๊ทธ ๊ฐ์ด name: ssosso์ธ์ง ํ์ธํด์ฃผ๋ฉด ํ ์คํธ๊ฐ ์๋ฃ๋๋ค.
๐ ์ฐธ๊ณ : ์ global.fetch๋ฅผ ํด์ค์ผ ํ ๊น?
fetchUser() ๊ฐ์ ํจ์๋ ๋ด๋ถ์์ fetch()๋ฅผ ํธ์ถํ๋๋ฐ,
ํ ์คํธ ํ๊ฒฝ์์ ์ค์ fetch๋ฅผ ์จ๋ฒ๋ฆฌ๋ฉด,
์ง์ง๋ก ์๋ฒ์ ์์ฒญ์ ๋ณด๋ด๋ ค๊ณ ํ๋ค.
๊ทธ๋ฐ๋ฐ ์๋ฒ๊ฐ ์๊ฑฐ๋ ์๋ต์ด ๋๋ฆฌ๋ฉด,
ํ ์คํธ๋ ์คํจํ๊ฑฐ๋ ๋๋ ค์ง๊ณ , ๋ถ์์ ํด์ง๋ค.
๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ global.fetch = vi.fn(() => Promise.resolve(...)); ๋ฅผ ํด์ค์ผ๋ก์จ
ํ ์คํธ ์ค์๋ ์ค์ fetch() ๊ฐ ์คํ๋์ง ์๊ณ ,
์ฐ๋ฆฌ๊ฐ ์ง์ ํ ์๋ต์ ์ฆ์ ๋ฐํํ๊ฒ ํด์ฃผ๋ ๊ฒ์ด๋ค.
์ด๋, ๋ธ๋ผ์ฐ์ ์์๋ window.fetch๊ฐ fetch ํจ์์ด์ง๋ง,
Node ํ๊ฒฝ์์๋ global.fetch์ด๊ธฐ ๋๋ฌธ์
ํ ์คํธ๋ Node ํ๊ฒฝ์์ ๋์๊ฐ๋๊น global.fetch๋ฅผ ๋ฎ์ด์ฐ๋ ๊ฒ์ด๋ค.
2๏ธโฃ ํน์ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ์ง ์๊ณ , ๋จ์ํ ํํ๋ก ๋์ฒดํ๊ณ ์ถ์ ๋
// App.tsx
import LoginPage from '@/pages/login/LoginPage';
export default function App() {
return <LoginPage />;
}
App ์ปดํฌ๋ํธ๋ ๋ก๊ทธ์ธ ํ์ด์ง๋ฅผ ๋ณด์ฌ์ฃผ๋๋ก ๊ตฌ์ฑ๋์ด ์๋๋ฐ,
์ค์ LoginPage๊ฐ ๋งค์ฐ ๋ณต์กํ๊ฑฐ๋ ๋ด๋ถ API ์์ฒญ, ๋ผ์ฐํ ๋ฑ์ด ํฌํจ๋์ด ์๋๋ผ๋
์ฐ๋ฆฌ๋ ๋ด๋ถ ๋์๊น์ง ๋ค ํ ์คํธํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์
mock์ ํ์ฉํด์ ํ ์คํธ๋ฅผ ํ๋ ๊ฒ์ด๋ค.
// App.test.tsx
jest.mock('@/pages/login/LoginPage', () => {
const Dummy = () => <div>Mocked Login Page</div>;
return { __esModule: true, default: Dummy };
});
test('App์ LoginPage๊ฐ ๋ ๋๋ง๋๋์ง ํ์ธ', () => {
render(<App />);
expect(screen.getByText('Mocked Login Page')).toBeInTheDocument();
});
jext.mock() ๐๐ป ํด๋น ๋ชจ๋์ ๊ฐ์ง๋ก ๋์ฒดํ๊ฒ ๋ค๋ ์ ์ธ
Dummy ๐๐ป ์ค์ LoginPage ๋์ ์ฌ์ฉํ ๊ฐ์ง ์ปดํฌ๋ํธ
__esModule: true, default: Dummy ๐๐ป ES Module ๋ฐฉ์์ default export๋ฅผ ํ๋ด๋ธ ๊ฒ
์ด๋ ๊ฒ ํด์ค์ผ๋ก์จ ์ฐ๋ฆฌ๊ฐ ํ ์คํธํ ๋๋
์ค์ LoginPage๊ฐ ๋ ๋๋ง๋๋ ๋์ ์
๊ฐ์ง๋ก ๋ฐ๊พผ Dummy ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋๊ณ ,
์ฐ๋ฆฌ๋ ๊ทธ ์์ ํ ์คํธ "Mocked Login Page"๊ฐ ๋ํ๋๋์ง๋ง ํ์ธํ๋ฉด ๋๋ค.
3๏ธโฃ ๋ณต์กํ ๋ด๋ถ ๋ก์ง์ ์๋ตํ๊ณ , ์์๋๋ ๊ฒฐ๊ณผ๋ง ์ง์ ํด์ ํ ์คํธํ๊ณ ์ถ์ ๋
// calculator.ts
export const complexOperation = (a: number, b: number) => {
// ๋ด๋ถ์ ์ผ๋ก ๋งค์ฐ ๋ณต์กํ ์ํ ์ฐ์ฐ์ ์ํํจ
return a * b + Math.sqrt(a + b);
};
complexOperation์ด ๋ด๋ถ์ ์ผ๋ก ๋งค์ฐ ๋ณต์กํ ์ํ ์ฐ์ฐ์ ์ํํ๋ค๊ณ ๊ฐ์ ํ๋ฉด,
๊ทธ ๊ฒฐ๊ณผ๋ ์์ธกํ๊ธฐ๊ฐ ์ด๋ ต๊ธฐ ๋๋ฌธ์ ํ ์คํธ์ ์ฌ์ฉํ๊ธฐ ์ ํฉํ์ง ์์ ๊ฒ์ด๋ค.
// component.tsx
import { complexOperation } from './calculator';
export function DisplayResult() {
const result = complexOperation(2, 3);
return <div>Result: {result}</div>;
}
์ด ์ปดํฌ๋ํธ๋ ์ค์ ๋ก ๋งค์ฐ ๋ณต์กํ๋ค๊ณ ๊ฐ์ ํ
complexOperation(2, 3)์ ๊ฒฐ๊ณผ๋ฅผ ํ๋ฉด์ ๋ณด์ฌ์ค๋ค๊ณ ํ์.
// component.test.tsx
jest.mock('./calculator', () => ({
complexOperation: jest.fn(() => 42), // ๊ฒฐ๊ณผ๋ง ์ง์
}));
test('๊ฒฐ๊ณผ๊ฐ ์ง์ ๋ ๊ฐ์ผ๋ก ํ์๋๋์ง ํ์ธ', () => {
render(<DisplayResult />);
expect(screen.getByText('Result: 42')).toBeInTheDocument();
});
jest.mock('./calculator', ...) ๐๐ป calculator ๋ชจ๋ ์ ์ฒด๋ฅผ mocking
complexOperation: jest.fn(() => 42) ๐๐ป ์ค์ ํจ์๊ฐ ๋ณต์กํ๊ฒ ๊ณ์ฐํ๋ ๊ฑธ ๋ง๊ณ , ๊ทธ๋ฅ 42๋ผ๋ ๊ฐ๋ง ๋ฐํํ๋๋ก ๋ฐ๊ฟ์น๊ธฐ ํด์ค
์ด๋ ๊ฒ ๋ณํํด์ฃผ๋ฉด, ๊ทธ๋ฅ Result: 42 ๊ฐ ํ๋ฉด์ ๋ํ๋๋์ง๋ง ํ์ธํ๋ฉด ๋๊ธฐ ๋๋ฌธ์
์ค์ ์ฐ์ฐ์ ํ๋ ๊ฒ๋ณด๋ค ๋น ๋ฅธ ํ ์คํธ๊ฐ ๊ฐ๋ฅํด์ง๋ค.
๐ก Mock์ ์ฌ์ฉํ๋ ์ด์
โ ํ ์คํธ ์๋ ํฅ์ ๐๐ป ์ค์ API ํธ์ถ ๋ฑ ๋๋ฆฐ ์์ ์์ด ํ ์คํธ ๊ฐ๋ฅ
โ ์์ ์ฑ ํ๋ณด ๐๐ป ์ธ๋ถ ์์คํ ์ฅ์ ๋ ๋ถ์์ ์ ์ํฅ์ ๋ฐ์ง ์์
โ ๋ ๋ฆฝ์ฑ ๋ณด์ฅ ๐๐ป ํ ์คํธํ๋ ค๋ ๋์๋ง ์ง์คํด์ ๊ฒ์ฆ ๊ฐ๋ฅ
โ ์คํจ ์์ธ ์ถ์ ์ฉ์ด ๐๐ป ์ง์ง ๊ตฌํ๊ณผ ๊ด๊ณ ์์ด ์์ธก ๊ฐ๋ฅํ ๊ฒฐ๊ณผ๋ก ํ ์คํธ ๊ฐ๋ฅ
๐ง Mock๊ณผ ๊ด๋ จ๋ ์ฉ์ด๋ค
| ์ฉ์ด | ์ค๋ช |
| Stub | ํน์ ํจ์๊ฐ ํธ์ถ๋๋ฉด ์ ํด์ง ๊ฐ์ ๋ฐํํ๋๋ก ๋ง๋ ๊ฐ์ง |
| Spy | ํจ์๊ฐ ์ด๋ป๊ฒ ํธ์ถ๋์๋์ง๋ฅผ ๊ธฐ๋กํ ์ ์๋ ๊ฐ์ฒด |
| Mock Function | ํธ์ถ ํ์, ์ธ์, ๋ฐํ๊ฐ ๋ฑ์ ์์ ๋กญ๊ฒ ์ค์ ํ ์ ์๋ ๊ฐ์ง ํจ์ |
| Fake | ์ค์ ๋์์ ํ์ง๋ง ๊ตฌํ์ด ๋จ์ํ๋ ๋์ฒด ๊ฐ์ฒด |
'๐ป๊ณต๋ถ ๊ธฐ๋ก > ๐ Frontend' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Frontend] ํ์ ์คํฌ๋ฆฝํธ์์ const ๋? (0) | 2025.06.16 |
|---|---|
| [Frontend] ์ปดํฌ๋ํธ๋ (1) | 2025.06.16 |
| [Frontend] ํ ์คํธ ์ฝ๋ ์์ฑํ๊ธฐ - Testing Library & Jest (2) | 2025.06.14 |
| [Frontend] prettier ์ ์ฉํ๊ธฐ (3) | 2025.06.14 |
| [Frontend] ํจํค์ง ๋งค๋์ ์ ๋์ ๊ณผ์ (2) | 2025.06.04 |