4.1 KiB
4.1 KiB
name, description
| name | description |
|---|---|
| dev-unit-test | Vue 3 컴포넌트를 받아 Vitest + Vue Test Utils 기반의 단위 테스트를 자동 생성합니다. Props, Emits, 슬롯, 사용자 인터랙션, 비동기 동작을 모두 커버합니다. 다음 상황에서 반드시 사용하세요: - "이 컴포넌트 단위 테스트 작성해줘", "테스트 코드 만들어줘" - "Vitest 어떻게 써?", "Vue Test Utils 사용 방법" - 컴포넌트 완성 후 커버리지를 확보해야 할 때 |
단위 테스트 생성 (dev-unit-test)
.vue 컴포넌트 → Vitest + Vue Test Utils 단위 테스트 자동 생성.
언제 사용하는가
- 컴포넌트 개발 완료 후 테스트 코드를 작성할 때
- TDD 방식으로 테스트를 먼저 작성할 때
- 프로젝트 테스트 커버리지 목표를 달성해야 할 때
입력
- 테스트할
.vue파일 경로 - 테스트 케이스 범위 (없으면 자동 도출)
작업 순서
Phase 1: 컴포넌트 분석
-
대상
.vue파일을 읽어 아래 항목을 파악한다.- Props 목록 (타입, 기본값, 필수 여부)
- Emits 목록 (이벤트 이름, 페이로드 타입)
- 슬롯 유무
- 외부 의존성 (composables, store, $fetch)
- 인터랙션 (버튼 클릭, 입력, 폼 제출)
- 비동기 동작 (API 호출, 로딩 상태)
- 조건부 렌더링 (
v-if,v-show)
-
테스트 케이스 목록을 도출한다.
Phase 2: 테스트 설정
// vitest.config.ts (없으면 생성 안내)
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
test: {
environment: 'jsdom',
globals: true,
},
})
Phase 3: 테스트 파일 생성
파일 위치: 컴포넌트와 동일 디렉토리 또는 __tests__/ 폴더.
파일명: <ComponentName>.spec.ts
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import ComponentName from './ComponentName.vue'
describe('ComponentName', () => {
// Phase 4 케이스 작성
})
Phase 4: 테스트 케이스 작성 패턴
Props 검증
it('title prop을 렌더링한다', () => {
const wrapper = mount(ComponentName, {
props: { title: '테스트 제목' }
})
expect(wrapper.find('h2').text()).toBe('테스트 제목')
})
it('필수 prop 누락 시 기본값을 사용한다', () => {
const wrapper = mount(ComponentName)
expect(wrapper.find('[data-testid="label"]').text()).toBe('기본값')
})
Emits 검증
it('버튼 클릭 시 click 이벤트를 emit한다', async () => {
const wrapper = mount(ComponentName, { props: { id: '1' } })
await wrapper.find('button').trigger('click')
expect(wrapper.emitted('click')?.[0]).toEqual(['1'])
})
조건부 렌더링
it('isLoading이 true이면 스피너를 표시한다', () => {
const wrapper = mount(ComponentName, { props: { isLoading: true } })
expect(wrapper.find('[aria-busy="true"]').exists()).toBe(true)
expect(wrapper.find('[data-testid="content"]').exists()).toBe(false)
})
비동기 / 스토어 Mock
import { createTestingPinia } from '@pinia/testing'
it('마운트 시 fetchProducts를 호출한다', async () => {
const wrapper = mount(ComponentName, {
global: {
plugins: [createTestingPinia({ createSpy: vi.fn })]
}
})
const store = useProductStore()
expect(store.fetchProducts).toHaveBeenCalledOnce()
})
슬롯
it('default 슬롯 콘텐츠를 렌더링한다', () => {
const wrapper = mount(ComponentName, {
slots: { default: '<span>슬롯 내용</span>' }
})
expect(wrapper.find('span').text()).toBe('슬롯 내용')
})
출력 형식
## 단위 테스트: <ComponentName>.spec.ts
### 테스트 케이스 목록
1. [렌더링] 기본 렌더링 성공
2. [Props] title prop 표시
3. [Emits] 버튼 클릭 시 emit
4. [조건부] isLoading 상태 처리
...
### 코드
\`\`\`ts
[전체 spec 파일]
\`\`\`
### 실행 방법
\`\`\`bash
npx vitest run <파일경로>
npx vitest --coverage # 커버리지 확인
\`\`\`