안녕하세요 ㅎㅎ
오늘은 조금 색다른 주제로 Vue 에서 테스트하는 방법에 대해 소개를 해드릴까 합니다.
최근에 Admin 프론트 관련한 개발을 진행하다 보니,
Front End 도 어떻게 하면 효과적으로 테스트해볼 수 있을까? 하는 백엔드 엔지니어 입장에서 작성해보았어요.
그래서 Front 개발자가 아니다 보니까 부족한점은 많을텐데요 ㅎㅎ.. 참고하시면서 봐주세요 :)
Jest
Jest 는 Javascript 진영에서 테스트 framework 입니다.
Jest 에서 지원해주는 특징 중의 하나가 바로 Scope 를 지정할 수 있다는 것인데요
대표적으로 describe 메서드입니다.
describe("A Component", () => {
it("단위 테스트에요", () => {
expect(true).toBe(true)
})
test("나도 테스트이지롱", async () => {
expect(true).toBe(true)
})
})
위와 같이 테스트하고자 하는 대상의 Scope 를 지정할 수 있습니다.
그렇기 때문에 DCI(Describe - Context - It) Pattern 의 테스트 도 쉽게 작성할 수 있다는 장점이 있죠 :)
DCI Pattern 에 대하여 간략하게 설명을 드리면
구성요소 | 설명 |
Describe | 테스트 하고자 하는 대상을 명시한다. |
Context | 대상이 놓인 상황을 설명한다. |
It | 상황을 기반으로 어떤 행동이 펼쳐지는지 명시한다. |
즉 테스트 코드 자체를 대상 - 상황 - 행동 에 따른 계층적으로 표현할 수 있게 됩니다.
Jest 는 역시 마찬가지로 위와 같은 describe, it 메서드를 통하여 DCI Pattern의 테스트 구조를 쉽게 잡을 수 있게 되는 것이죠 :)
단위 테스트는 기본적으로 아래와 같은 속성을 만족해야되는데요.
- Fast(빠름)
- Isolated(독립성)
- Repeatable(재가동성)
- Self-Validating
- Timely
여기서 제일 중요한 속성 2가지는 빠르고 독립적이어야 합니다.
그래서 테스트를 독립적으로 작성하기 위해서는 적절하게 mock 을 활용하여 진행해야 되는데, 이 부분은 API 에 대한 설명을 쭉 늘어야하기 때문에 링크로 대체합니다 ㅎㅎ
https://jestjs.io/docs/mock-function-api
Matchers 에 대한 부분도 다양하게 제공하는데, 이 부분 또한 너무 게시글이 늘어지기도 하고, 공식문서에 예제와 함께 정리가 잘 되어 있어서 링크로 대체합니다
그래서 Jest 를 기반으로 우리는 독립적이고, 계층 구조가 잡힌 테스트를 쉽게 작성할 수 있습니다.
그렇다면, Vue 에서 제공하는 테스트 유틸들은 어떤 것이 있을지 알아볼게요.
Vue Test Utils
VTU(Vue Test Utils) 는 Vue framework 를 테스트하기 위한 라이브러리 입니다.
Component 기반의 랜더링 지원부터 시작해서, user 의 interaction 까지 테스트해볼 수 있습니다.
import { mount } from '@vue/test-utils'
// The component to test
const MessageComponent = {
template: '<p>{{ msg }}</p>',
props: ['msg']
}
describe('messageComponent', () => {
test('displays message', () => {
const wrapper = mount(MessageComponent, {
props: {
msg: 'Hello world'
}
// Assert the rendered text of the component
expect(wrapper.text()).toContain('Hello world')
})
})
위의 예시처럼 말이죠 ㅎㅎ
VTU 의 경우에는 하나씩 차근차근 API 의 구성요소를 하나씩 살펴보도록 해볼게요
https://test-utils.vuejs.org/api/
Mount
Mount 는 Component 의 단위 테스트를 진행하기 위해 랜더링을 해주는 역할입니다.
일반적으로 Component 가 실제 환경에서 랜더링 될 때 다양한 변수 혹은 값들이 존재하는데, 이를 쉽게 제공해줄 수 있습니다.
import {mount} from "@vue/test-utils";
const wrapper = mount(
ComponentA,
{
global: {
provide: {},
stubs: {}
},
props: {},
shallow: false
}
)
구성요소 | 설명 |
global | Vue 에서 제공하는 전역변수에 대한 제공하거나 자식 Component 에 대한 stub 속성 제공 |
props | Component 가 만들어질 때 넘어오는 props value 설정 |
slots | Slot 에 대한 설정 제공 |
shallow | 자식 Component 를 모두 stub 할 것인지 여부. default 는 false |
여기서 크게 눈여겨 보아할 점은 바로 shallow 속성인데요.
Jest 에도 설명드렸다 싶이, 테스트는 독립성을 지니게 만들어야 합니다.
따라서 테스트하고자 하는 대상 Component 에 자식 Component 가 포함되어 있다면,
자식 Component 는 테스트 scope 에 포함되지 않도록 항상 stub 하는 것이 중요합니다.
그래서 일반적으로는 shallow: true 를 사용하시거나, shallowMount 함수를 이용하게 됩니다 :)
Wrapper
Wrapper 는 mount 의 리턴값으로 얻게 되는 데이터인데요.
쉽게 설명드리면, Wrapper 는 Component instance 에 대한 Test Wrapper 라고 보시면 됩니다.
DOM Node 들을 쉽게 찾아내고, 데이터를 세팅하는 메서드들이 잔뜩 준비되어 있습니다.
메서드 | 설명 |
find / findAll | element 를 있다면 DomWrapper 를 리턴합니다. |
exists | 해당 element 가 존재하는 여부. true or false |
setValue | input 태그에 데이터를 입력하거나 select 태그에 option 데이터를 선택합니다. |
trigger | click / submit / keyup 과 같은 Dom event 를 트리거링 합니다. |
text | 특정 element 의 text 데이터만 가져옵니다. |
html | 특정 element 의 html 정보를 가져옵니다. |
예제 코드를 몇가지 살펴보면 아래와 같이 활용할 수 있습니다.
<template>
<span />
</template>
위와 같은 Component 가 있다고 가정했을 때,
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('exists', () => {
const wrapper = mount(Component)
expect(wrapper.find('span').exists()).toBe(true)
expect(wrapper.find('p').exists()).toBe(false)
})
exists 메서드를 통하여 특정 태그가 담겨있는지 검증할 수도 있습니다.
특정 Component의 form 태그 또한 위에서 소개드린 메서드 기반으로 테스트할 수 있는데요.
<template>
<input type="text" v-model="text" />
<p>Text: {{ text }}</p>
<input type="checkbox" v-model="checked" />
<div v-if="checked">The input has been checked!</div>
</template>
<script lang="ts">
import {defineComponent} from "vue";
export default defineComponent({
name: "InputComponent",
setup() {
return {
text: '',
checked: false
}
}
})
</script>
위와 같이 input 태그에서 text 를 입력하는 text 와 checkBox 를 표시하는 input 태그가 있다고 가정하면..
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('setValue on checkbox', async () => {
const wrapper = mount(Component)
await wrapper.find('input[type="checkbox"]').setValue(true)
expect(wrapper.find('div')).toBe(true)
await wrapper.find('input[type="checkbox"]').setValue(false)
expect(wrapper.find('div')).toBe(false)
})
test('setValue on input text', () => {
const wrapper = mount(Component)
await wrapper.find('input[type="text"]').setValue('hello!')
expect(wrapper.find('p').text()).toBe('Text: hello!')
})
위와 같이 checkbox 를 선택하거나, text 에 특정 값을 기입하는 테스트 또한 가능합니다
자세한 내용들은 공식문서에 정리되어 있으니 꼭 참고해주세요 :)
https://test-utils.vuejs.org/api/
정리하며
Vue 에서 Component 를 테스트 하기 위해서는 2가지 Framework 을 이용해야 합니다.
- Jest: JavaScript 기반으로 테스트 구조를 잡고, 적절하게 mock, matchers 기능을 활용
- Vue Test Utils: Vue Component 를 랜더링 해주고, Vue 에서 제공하는 global 변수들을 설정하여 Component 테스트 환경 setup
둘다 공식 문서가 너무 잘되어 있기에 꼭 꼭 참고하면 좋겠습니다.
참고 자료
Jest와 VTU로 Component 단위 테스트
Vue Test Utils
Jest
'Developer > Frontend' 카테고리의 다른 글
백엔드가 정리하는 Vue3 - Composition API (4) | 2021.09.25 |
---|