Vueでunitテストをする為の基礎基礎メモ
準備
- vue-cliでプロジェクトを作成する
- Jestを利用する。
- vue-test-utilsを利用する(vue-cliでプロジェクトを作成した場合はインストール済み)
Jestとは
vue-test-utilsとは
公式より
vue-test-utilsは Vue.js 向けの公式単体テストライブラリです。
テストを書く
プロジェクト作成時は、以下にtest用のファイルがあります。 こちらを参考にするとわかりやすいかもしれません。
/tests/unit/example.spec.js
describe
テストの概要を記載します。 テストをまとめる単位としても利用します。
it
テストケースです。 テストの目的を記載します。
例
describe('テストの概要', () => { it('テストケース1', () => { }) })
テストを実行
以下のCommandでテストを実行できます。
npm run test:unit
実行結果
テストがうまく動くと下記のような表示になります。
PASS tests/unit/example.spec.js テストの概要 ✓ テストケース1 (1ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 1.285s
テストを書く (その2)
上記ではテスト内容がないものを実行していましたが、今度はテスト内容を追加していきます。
Vueコンポーネントをマウントする
Vueコンポーネントをテストするには、まずVueコンポーネントをマウントする必要があります。 マウントするには、mount
、shallowMount
のいずれかを利用します。
mount
、shallowMount
はvue-test-utilsの関数なので、利用するにはライブラリをインポートする必要があります。
import { shallowMount } from '@vue/test-utils'
関数名 | 説明 | 利用ケース |
---|---|---|
mount | 子コンポーネントに実際のコンポーネントを使う | コンポーネント同士で連携が必要な場合 |
shallowMount | 子コンポーネントにダミーのコンポーネントを使う | コンポーネント単体でのテスト |
※mountを利用した場合は、テスト対象のコンポーネントの子コンポーネントの変更もテストに影響を受けます。
以下でコンポーネントをマウントします。 戻り値として、コンポーネントラッパーを返却します。 このラッパーを利用してテストを行います。
const wrapper = shallowMount(HelloWorld)
Assertionを作成
コンポーネントが期待する動作をするかを判定するにはAssertionを作成する必要があり、その為にexpect
APIを利用します。
expect(result).to [matcher] (actual)
例
new messageの文字列が画面内にあるかをテスト。
HelloWorld.spec.js
import { shallowMount } from '@vue/test-utils' import HelloWorld from '@/components/HelloWorld.vue' describe('HelloWorld.vue', () => { it('テストケース1', () => { const msg = 'new message' const wrapper = shallowMount(HelloWorld, { propsData: { msg } }) // HelloWorldコンポーネント内のテキストを正規表現でチェック(.toMatch(regexp)) expect(wrapper.text()).toMatch(msg) }) })
HelloWorld.vue
<template> <h1>{{ msg }}</h1> </template> <script> export default { name: 'HelloWorld', props: { msg: String } } </script>
テストマッチャー
テストで様々な値をテストとする為にMatcherを利用します。 Matcherは以下の形式で利用します。
expect(result).to [matcher] (actual)
Matcher | 説明 | 使用例 |
---|---|---|
.toBe(value) | resultとactual等価であることの比較 | expect(4).toBe(4) |
.toEqual(value) | resultとactualの連想配列の中身が一致するかの比較 | expect({two: 2,one: 1}).toEqual({one: 1,two: 2}) |
.toMatch(regexp) | resultに対して正規表現で比較 | expect('abcdefg').toMatch(/abc/) |
.toBeGreaterThan(number) | resultがactualより大きい | expect(11).toBeGreaterThan(10) |
.toBeGreaterThanOrEqual(number) | resultがactual以上 | expect(10).toBeGreaterThanOrEqual(10) |
.toBeLessThan(number) | resultがactualより小さい | expect(9).toBeLessThan(10) |
.toBeLessThanOrEqual(number) | resultがactual以下 | expect(10).toBeLessThanOrEqual(10) |
.toBeCloseTo(number,桁数) | resultの特定の少数桁までactualと一致するかを比較(jsは小数点計算で誤差がでる為) | expect(0.1 + 0.2).toBeCloseTo(0.35, 1) |
.toHaveLength(number) | resultのlengthとactualと一致するかを比較 | expect([1,2]).toHaveLength(2) |
.toBeInstanceOf(class) | resultがactualと同じclassのインスタンス化か比較 | class Klass {} expect(new Klass()).toBeInstanceOf(Klass) |
.toHaveProperty(value) | resultの特定のkeyと一致するか | expect({a:false,b:{c:1,d:'A'}}).toHaveProperty('a') // key aがあるか expect({a:false,b:{c:1,d:'A'}}).toHaveProperty('a',false) // key aはfalseか expect({a:false,b:{c:1,d:'A'}}).toHaveProperty('b.c',1) |
.toMatchObject(value) | resultの一部とactualが一致するか | expect({a:1,b:2}).toMatchObject({a: 1}) |
.toContain(value) | resultにactualが入っているか | expect([1,2]).toContain(2) expect('ABCDEFG').toContain('EFG') |
.toBeNull() | resultがNullかどうか | expect(null).toBeNull() |
.toBeUndefined() | resultがUndefinedかどうか | expect().toBeUndefined() |
.not
を利用して否定で判定することもできます。
expect(2).not.toBe(1)
Matcherは他にもたくさんあります。 こちらを確認してください。
vue-test-utilsの使い方
vue-test-utilsはVue.jsの公式単体テスト用ライブラリです。 vue-cliを利用した場合は、プロジェクトに含まれています。
propsDataの使い方
mount
やshallowMount
で利用することができる。 propsDataは親コンポーネントから、propsとして渡されたものとして利用することができる。
HelloWorld.vue
<template> <div> <span v-if="flag === true">{{msg}}</span> </div> </template> <script> export default { name: 'HelloWorld', props: { msg: String, flag:Boolean } } </script>
HelloWorld.spec.js
ERROR
new message
の文言が画面内に無いので、これはエラーになります。
import { shallowMount } from '@vue/test-utils' import HelloWorld from '@/components/HelloWorld.vue' describe('HelloWorld.vue', () => { it('テストケース1', () => { const msg = 'new message' const wrapper = shallowMount(HelloWorld, { propsData: { msg } }) expect(wrapper.text()).toMatch(msg) }) })
OK
new message
の文言が画面内に無いので、これは成功します。
import { shallowMount } from '@vue/test-utils' import HelloWorld from '@/components/HelloWorld.vue' describe('HelloWorld.vue', () => { it('テストケース1', () => { const msg = 'new message' const flag = true const wrapper = shallowMount(HelloWorld, { propsData: { msg ,flag} }) expect(wrapper.text()).toMatch(msg) }) })
使いそうなWrapperメソッド
HelloWorld.vueはこちらとします。
<template> <div> <span>{{msg}}</span> <span @click="changeMsg">{{clickMsg}}</span> </div> </template> <script> export default { name: 'HelloWorld', props: { msg: String }, data(){ return{ clickMsg :'' } }, methods:{ changeMsg(arg){ this.clickMsg = `${arg.hogehoge}回クリックしたよ` } } } </script>
props()
Vueコンポーネントのインスタンスのpropsを返却します。
describe('HelloWorld.vue', () => { it('テストケース', () => { const msg = 'new message' const wrapper = shallowMount(HelloWorld, { propsData: { msg } }) expect(wrapper.props().msg).toBe('new message') }) })
setProps(props)
Vueコンポーネントのインスタンスにpropsを設定します。
すでにマウントされているコンポーネントのプロパティを更新することができます。
describe('HelloWorld.vue', () => { it('テストケース', () => { const wrapper = shallowMount(HelloWorld) wrapper.setProps({ flag: true }) expect(wrapper.vm.flag).toBe(true) }) })
ただし、mount時にsync:false
を設定ししてると反映されません。
find(selector)、findAll(selector)
find()と findAll()は、インスタンスのDOMの中から、selectorと一致する DOMまたはVueコンポーネントを取得するのに利用します。
describe('HelloWorld.vue', () => { it('テストケース', () => { const msg = 'new message' const wrapper = shallowMount(HelloWorld, { propsData: { msg } }) const elm = wrapper.find('span') expect(elm.is('span')).toBe(true) }) })
trigger(eventType [, options ])
DOMのイベントを発火することができます。
describe('HelloWorld.vue', () => { it('テストケース', () => { const msg = 'new message' const wrapper = shallowMount(HelloWorld, { propsData: { msg } }) const elm = wrapper.findAll('span').at(1) elm.trigger('click') expect(wrapper.text()).toMatch('クリックしたよ') }) })
以下のような感じで引数を渡すこともできます。
describe('HelloWorld.vue', () => { it('テストケース', () => { const msg = 'new message' const wrapper = shallowMount(HelloWorld, { propsData: { msg } }) const elm = wrapper.findAll('span').at(1) elm.trigger('click',{hogehoge:2}) expect(wrapper.text()).toMatch('2回クリックしたよ') }) })
他にもたくさんあります。 こちらを参照してください。
まとめ
ほん〜〜〜の一部だけまとめてみました。 テスト難しいです。