๋ชฉ์ฐจ
- Introduction
- What is Test Double
- Stub
- Spy
- Mock
- Conclusion
- Reference
๐Introduction
์ด๋ฒํธ์TDD๋ฅผ ํ๊ธฐ์ํด test double์ด๋ผ๋ ๊ฒ์ ๋ํด ๋ถ๊ฐ์ ์ผ๋ก ์์๋ณด๋ ํฌ์คํ ์ ๋๋ค.
๐What is Test Double?
ํ ์คํธ ๋๋ธ์ด๋ ์ค์ ๊ฐ์ฒด๋ฅผ ๋์ ํด์ ํ ์คํ ์์ ์ฌ์ฉํ๋ ๋ชจ๋ ๋ฐฉ๋ฒ์ ๋งํฉ๋๋ค. ์๋ฅผ ๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ ์ค์ api ํต์ ์ ํ๋ ํจ์๊ฐ ์๋ค๊ณ ๊ฐ์ ํด๋ด ์๋ค.
asnyc function getTodos() {
await axios.get('jsonplace-holder/todos');
}
getTodos
๋ฅผ ํ
์คํ
ํ๋ ค๋ฉด ์ค์ ๋คํธ์ํฌ api๋ฅผ ์ฌ์ฉํ๊ฒ ๋ฉ๋๋ค. ์ด๊ฒ์ ๋คํธ์ํฌ ์ฐ๊ฒฐ ์ํ์ ์ํฅ์ ๋ฐ์ ๊ฒ์ด๊ณ ํญ์ ๊ฐ์ ์กฐ๊ฑด์์ ํ
์คํ
๋์ด์ผ ํ๋ค๋ ์กฐ๊ฑด์ ์๋ฐํ๊ฒ ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ค์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ธฐ ์ด๋ ต๊ณ ๋ชจํธํ ๋ ๋์ ํด์ค ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ํ
์คํธ๋ฅผ ๋์ต๋๋ค.(์ด๊ฒ์ด ํ
์คํธ ๋๋ธ...!๐)
ํ ์คํธ ๋๋ธ์๋ 5๊ฐ์ง ์ข ๋ฅ๊ฐ ์์ต๋๋ค.
- Dummy
- Fake
- Stub
- Spy
- Mock
๊ฐ๊ฐ์ ์ข
๋ฅ์ ๋ํด ์ดํด๋ณด๊ณ ์ด๋ป๊ฒ Vue ํ
์คํ
์ ์ ์ฉ์ด ๋๋์ง(์ฃผ๋ก Vuex๋ฅผ ๋ค๋ฃธ) ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ด์ค stub, spy, mock์ ๋ํด์ ์ค๋ช
ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.(Vue testing์ ํ ๋ dummy ์ fake๋ฅผ ์ฌ์ฉํด๋ณธ์ ์ด ์๊ธฐ๋๋ฌธ...)
๐1. Stub
Stub
๋ ์ค์ ๋ก๋ ๋์ํ์ง ์์ง๋ง, ๋์ํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๊ธฐ ์ํด ์ค๋น๋ ๊ฐ๋ง์ ๋ฐํํ๋ ๊ฐ์ฒด์
๋๋ค.
์ฃผ๋ก stub๋ฅผ ์ฌ์ฉํ ๋๋ ์ธ๋ถ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋ ๋ง์ด ์ฐ๊ฒ๋ฉ๋๋ค. ์ผ๋จ nanoid๋ฅผ stubํ๋ ์์ ๋ฅผ ๋ณด์ฌ๋๋ฆฌ๊ฒ ์ต๋๋ค.
import { nanoid } from 'nanoid';
jest.mock('nanoid');
let value = 0;
nanoid.mockImplementation(() => {
const result = String((value += 1));
return result;
});
beforeEach(() => {
value = 0;
})
์ค์ nanoid๋ 12sdfmk1231000wdm๊ณผ ๊ฐ์ ์๊ธฐ ํ๋ id๊ฐ์ returnํ๊ฒ ๋ฉ๋๋ค. ๋ง์ฝ todo๋ฅผ ์์ฑํ ๋ ๋ง๋ค ์ด ๊ฐ์ด nanoid๊ฐ ๋ถ๋๋ค๋ฉด... ์ด๋ถ๋ถ์ ์ด๋ป๊ฒ ํ ์คํ ์ด ๋์ด์ผํ ๊น์?
์ ๋ต์ stub๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค!
์์ ์์ ์์ nanoid๊ฐ ๊ฐ test๋ง๋ค ์์๋๋ก '1', '2'....๋ฅผ ์์ฐจ์ ์ผ๋ก returnํ๊ฒ ๋ฉ๋๋ค. ์ค์ ๋ก ๋์ํ์ง ์์ง๋ง ์ ๊ฐ ์ค๋นํ value๊ฐ ๋ง์ ๋ฆฌํดํ๊ฒ ๋๋ ์์ ์ ๋๋ค.
๐2. Spy
Spy
๋ ํธ์ถ๋ฑ ์ผ๋ถ ์ ๋ณด๋ฅผ ๊ธฐ๋กํด ๋ค์ํ ์ํฉ์ ๊ฐ์ํ๋ ๊ฐ์ฒด์
๋๋ค.
์ฃผ๋ก jest๋ฅผ ์ฌ์ฉํ ๋๋ jest.fn ํน์ jest.spyOn์ ์ฌ์ฉํฉ๋๋ค.(Vue๊ณต์ ๋ฌธ์์ ๋์ ์๋ sinon๋ ์๊ธด ํ์ง๋ง ๋ค๋ฃจ์ง๋ ์๊ฒ ์)
๋ค์ ์์ ๋ฅผ ๋ณด๊ฒ ์ต๋๋ค.
describe('CHANGE_COUNT_VALUE test', () => {
it('change count value by 10', () => {
const commit = jest.fn();
CHANGE_COUNT_VALUE({ commit }, 10);
expect(commit).toHaveBeenCalledWith('SET_COUNT_VALUE', 10);
});
});
Vuex์ Actions๋ฅผ ํ
์คํ
ํ๋ ๋ด์ฉ์
๋๋ค. ์ฌ๊ธฐ์ const commit = jest.fn()์ ์ฃผ๋ชฉํด์ฃผ์ธ์.
jest.fn์ ์๋ ๋ชจ์ ํจ์๋ฅผ ๋ง๋ค๊ธฐ ์ํ ํจ์ ์
๋๋ค.(jest ๊ณต์๋ฌธ์ ์ฐธ๊ณ ) ํ์ง๋ง ์ด ๋ชจ์ ํจ์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํธ์ถ์ด ๊ฐ์๊ฐ ๋๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํ๊ธฐ๋ ํฉ๋๋ค.(jest.spyOn์ ์ฌ์ฉํด๋ ์๊ด์ ์์ต๋๋ค).
์ฃผ๋ก Actions๋ฅผ ํ ์คํ ์ ํ ๋ commit์ ๊ด์ฐฐ์ ํฉ๋๋ค. ์ด๋ค mutations๊ฐ ํธ์ถ์ด ๋์๊ณ ์ด๋ค ๊ฐ์ ๋๊ฒจ์ฃผ๋์ง์ ๊ดํด ํ ์คํ ์ ํ๊ฒ๋ฉ๋๋ค. ๊ทธ๋์ commit์ jest.fn()์ ์ฌ์ฉํ์ฌ spy๋ฅผ ํ๋ ๊ฒ ์ ๋๋ค.
๐3. Mock
Mock
์ ์ค์ ๋ก ๋์ํ์ง๋ง ์ค๋น๋ ๊ฐ๋ง์ ๋ฐํํ๋ ๊ฐ์ฒด์
๋๋ค.
๋ค์ ์์ ๋ฅผ ๋ณด๊ฒ ์ต๋๋ค.
import { fetchData } from '@/api/todo-service';
jest.mock('@/api/todo-service');
const { FETCH_ITEMS } = actions;
describe('Action test', () => {
describe('Async actions test', () => {
describe('Fetch items test', () => {
it('get items from mock', async () => {
fetchData.mockResolvedValue(mockItems);
const commit = jest.fn();
await FETCH_ITEMS({ commit });
expect(commit).toHaveBeenCalledWith('SET_ITEMS', mockItems.data);
});
});
});
fetchData
๋ json-placehoder์์ todos๋ฅผ ๋ถ๋ฌ์ค๋ api-call์ ํ๋ ํจ์์
๋๋ค. ๊ทธ๋์ ์ค์ ๋ก api-call์ ํ๋ ๊ฒ์ด ์๋ jest.mock('@/api/todo-service');
์ ํด์ค๋๋ค. ๊ทธ๋ฆฌ๊ณ fetchData๊ฐ ์ค์ ๋ก ๋ฐํํ๋ ๊ฐ์ด ๋ฌด์์ธ์ง๋ฅผ ๊ฒฐ์ ํ๋๊ฒ์ fetchData.mockResolvedValue(mockItems);
์ ์จ์ฃผ๊ฒ ๋ฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ค์ ๋ก๋ fetchData๋ api-call์ ํด์ data๋ฅผ ๋ถ๋ฌ์ค๊ฒ ๋์ง๋ง testing์์๋ ๋ฌด์กฐ๊ฑด mockItems๋ฅผ ๋ฐํํ๊ฒ ๋ฉ๋๋ค. ์ด๋ ๊ฒ jest.mock์ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ๊ฒ mock์ ํด์ค ์ ์์ต๋๋ค.
๐Conclusion
์ฌ์ค ์ด๋ ๊ฒ ํ ์คํ ์ ํ๋ฉด์ ์ ํํ ์ฉ์ด์ ๊ทธ์ ๋ฐ๋ฅธ ์ค๋ช ๋ค์ ๊น๊ฒ ๊ณต๋ถํ ํ์๋ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ค์ ๋ก vue test code๋ฅผ ์์ฑํ๋ค๋ณด๋ฉด '์ด๊ฑธ ๋๋์ฒด ์ด๋ป๊ฒ ํ ์คํ ํ์ง..?" ํ๋ ๋ถ๋ถ๋ค์ด ์๋๋ฐ ๊ทธ๋ถ๋ถ๋ค์ ์ด๋ป๊ฒ ํด๊ฒฐ์ ํ ๊น๋ฅผ ๊ณ ๋ฏผํ๋ค๋ณด๋ฉด ์์ฐ์ค๋ ์ตํ์ง๋ ๋ด์ฉ๋ค์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์ ๋ ํ ์คํธ ๋๋ธ์ด๋ผ๋ ๊ฒ์ ์ฒ์ ์ ํ๊ฒ ๋๊ฑด testing์ ๊ณต๋ถํ๊ณ ๋ ํ์ฐธ ๋ค์ ์ผ์ด์์ต๋๋ค. ์... ์ด๊ฑธ ํ ์คํธ ๋๋ธ์ด๋ผ๊ณ ๋ถ๋ฅด๋ ๊ฑฐ๊ตฌ๋.. ์ด๊ฑธ ์ด๋ฐ์์ผ๋ก ๋ถ๋ฅด๋๊ตฌ๋ ์ ๋๋ก๋ง ์๊ณ ์์๋๊ฑฐ ๊ฐ์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด๊ธ์ด ๋๋ฌด ์ง๋ถํ๋ค๊ณ ๋๋ผ์ง ์์ผ์ จ์ผ๋ฉด ์ข๊ฒ ๋ค๋ ์๊ฐ์... ํ๋ฉด์ ๊ธ์ ๋ง์นฉ๋๋ค.
๐ Reference
'Vue TDD' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
ํ์ฌ ํ๋ก์ ํธ Hydration ์คํจ Github Action์ผ๋ก ํ ์คํ ํ๊ธฐ (feat. cypress) (5) | 2022.01.19 |
---|---|
Vue TDD - ๋ฒ์ธ2 (mixins tesing) (0) | 2020.09.23 |
Vue TDD - ํ๊ณ ํธ (0) | 2020.08.10 |
Test code ์ฝ๊ฒ ์ฐ๊ธฐ - 1 (0) | 2020.08.06 |
Vue TDD - E2E ํธ (0) | 2020.08.02 |