티스토리 뷰
create-nuxt-app로 프로젝트를 설정할 때 단위 테스트 프레임워크를 선택할 수 있다. AVA, Jest 중에 선택할 수 있는데 React.js로 개발했을 때 사용한 Jest를 사용한 경험이 있었기 때문에 Jest로 선택했다. 참고로 Jest는 facebook에서 만들었다.
선택하지 않은 경우에는 테스트 관련 모듈을 수동으로 설치 및 설정해줘야 한다. 아래 모듈을 --save-dev로 추가하자.
- @vue/test-utils : vue 코드를 단위 테스트할 때 필요한 유틸을 제공한다.
- jest : 단위 테스트 작성에 필요한 matcher, teardown 등을 제공한다. mock, spy로 테스트하는 방법도 안내하고 있으니 공식 사이트를 방문해서 꼭 보도록 하자.
- vue-jest , babel-jest : vue, ES6 문법으로 작성된 코드를 jest 수행 시 변환해주는 플러그인 모듈입니다.
그리고 package.json에 scripts를 추가하자.
📄 package.json
"scripts": {
...
"test": "jest"
},
jest.config.js 파일을 생성한 후 아래 설정을 추가 하자.
📄 jest.config.js
module.exports = {
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js'
},
moduleFileExtensions: ['js', 'vue', 'json'],
transform: {
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue'
]
}
test 폴더를 생성한 후 간단한 테스트 파일을 만든다.
📄 test/TodoList.test.js
describe('test', () => {
test('test for test', () => {
expect(2 + 2).toBe(4)
})
})
npm run test로 실행했을 때 아래와 같은 화면을 만난다면 단위 테스트 환경 구축이 완료된 것이다.
추가로 Vuex 테스트하려면 몇 가지 설정이 필요하다. 테스트 코드에 import 사용하려면 바벨 설정을 해줘야 한다.
. babelrc 파일을 생성하고 아래처럼 설정하자.
📌참고
create-nuxt-app설정 시 테스트 모듈을 선택했다면 이미 설정이 되어있다.
📄 .babelrc
{
"env": {
"test": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}
}
}
설정을 하지 않은 경우 import 에러를 만날 수 있다.
글로벌 Vue를 오염시키지 않고 테스트 내부에서 사용하는 Vue를 생성하고 연결해야 하기 때문에 test-utils의 createLocalVue 메서드를 이용해야 한다.
📄 test/TodoList.test.js
import { createLocalVue, shallowMount } from '@vue/test-utils'
import Vuex from 'vuex'
import TodoList from '~/components/TodoList'
const localVue = createLocalVue()
localVue.use(Vuex)
describe('TodoList Component', () => {
let store
beforeEach(() => {
const state = {
todos: [],
visibility: 'all',
selectedTodo: null
}
store = new Vuex.Store({
state
})
})
test('should render data', () => {
shallowMount(TodoList, {
store, localVue
})
expect(true).toBe(true)
})
})
실행하면 아래와 같은 에러를 만난다.
Vuex.Store 시 state만 추가하고 TodoList에서 사용하는 getters가 존재하지 않기 때문이다. 구현한 스토어를 재사용하고 싶어서 getters, actions를 아래처럼 추가했다.
📄 test/TodoList.test.js
import { createLocalVue, shallowMount } from '@vue/test-utils'
import Vuex from 'vuex'
import { getters, actions } from '~/store'
import TodoList from '~/components/TodoList'
const localVue = createLocalVue()
localVue.use(Vuex)
describe('TodoList Component', () => {
let store
beforeEach(() => {
const state = {
todos: [{
id: 'todo-1584926194640',
text: 'API 방식으로 변경하기',
completed: true
}],
visibility: 'all',
selectedTodo: null
}
store = new Vuex.Store({
state,
getters,
actions
})
})
test('should render data', () => {
const wrapper = shallowMount(TodoList, {
store,
localVue
})
expect(wrapper.findAll('li').length).toBe(1)
})
})
만약 store가 복잡하게 구성된 경우라면 아래 포스팅을 참고해서 테스트용 빌더를 만들어 보는 것도 괜찮은 방법 같다.
todos 데이터가 없는 경우에는 정상 동작하지만 1개의 데이터를 추가한 후 테스트를 수행하면 아래와 같은 에러를 만난다.
nuxt-link 컴포넌트가 뭔지 모르겠다는 건데 해결 방법은 test-utils에서 제공해주는 RouterLinkStub 사용해서 nuxt-link를 stub 처리하는 것이다. 자세한 내용은 링크를 참고하자.
최종 코드는 다음과 같다.
📄 test/TodoList.test.js
import { createLocalVue, shallowMount, RouterLinkStub } from '@vue/test-utils'
import Vuex from 'vuex'
import { getters, actions } from '~/store'
import TodoList from '~/components/TodoList'
const localVue = createLocalVue()
localVue.use(Vuex)
describe('TodoList Component', () => {
let store
beforeEach(() => {
const state = {
todos: [{
id: 'todo-1584926194640',
text: 'API 방식으로 변경하기',
completed: true
}],
visibility: 'all',
selectedTodo: null
}
store = new Vuex.Store({
state,
getters,
actions
})
})
test('should render data', () => {
const wrapper = shallowMount(TodoList, {
store,
localVue,
stubs: {
NuxtLink: RouterLinkStub
}
})
expect(wrapper.findAll('li').length).toBe(1)
})
})