単体テスト

最終更新日: 2020年4月26日

Vue CLI には、Jest または Mocha を使って難しい設定なしにユニットテストするための組み込みのオプションがあります。カスタムセットアップのためのより詳細なガイダンスとなる公式の Vue Test Utils もあります。

単純なテスト

テスト設計の観点から、コンポーネントのテスタビリティを向上させるためにコンポーネント内で特別な何かを行う必要はありません。単純に options をエクスポートするだけです。

<template>
  <span>{{ message }}</span>
</template>

<script>
  export default {
    data () {
      return {
        message: 'hello!'
      }
    },
    created () {
      this.message = 'bye!'
    }
  }
</script>

コンポーネントをテストする際には、Vue Test Utils と合わせてインポートし、検証を実施します (ここでは、例として Jest スタイルの expect アサーションを使用しています):

// Vue Test Utils の `shallowMount` とテスト対象のコンポーネントをインポートします。
import { shallowMount } from '@vue/test-utils'
import MyComponent from './MyComponent.vue'

// コンポーネントをマウントします。
const wrapper = shallowMount(MyComponent)

// テストランナーや検証には、どのようなライブラリを用いても構いませんが
// ここでは Jest を用いたテスト記述を行っています。
describe('MyComponent', () => {
  // コンポーネントの options を直接検証します。
  it('has a created hook', () => {
    expect(typeof MyComponent.created).toBe('function')
  })

  // コンポーネントの options 内にある関数を実行し、
  // 結果を検証します。
  it('sets the correct default data', () => {
    expect(typeof MyComponent.data).toBe('function')
    const defaultData = MyComponent.data()
    expect(defaultData.message).toBe('hello!')
  })

  // コンポーネントインスタンスをマウントして検証します。
  it('correctly sets the message when created', () => {
    expect(wrapper.vm.$data.message).toBe('bye!')
  })

  // マウントされたコンポーネントインスタンスを描画して検証します。
  it('renders the correct message', () => {
    expect(wrapper.text()).toBe('bye!')
  })
})

テストしやすいコンポーネントの記述

コンポーネントの描画結果は、コンポーネントの受け取るプロパティによってその大半が決定されます。実際、コンポーネントの描画結果が、単にプロパティの値によってのみ決まる場合、異なる引数を用いた関数の戻り値の検証と同じ様に、シンプルに考えることができます。例を見てみましょう。

<template>
  <p>{{ msg }}</p>
</template>

<script>
  export default {
    props: ['msg']
  }
</script>

Vue Test Utils を利用して、異なるプロパティを用いた描画結果の検証が可能です。

import { shallowMount } from '@vue/test-utils'
import MyComponent from './MyComponent.vue'

// コンポーネントをマウントし描画結果を返すヘルパー関数
function getMountedComponent(Component, propsData) {
  return shallowMount(Component, {
    propsData
  })
}

describe('MyComponent', () => {
  it('renders correctly with different props', () => {
    expect(
      getMountedComponent(MyComponent, {
        msg: 'Hello'
      }).text()
    ).toBe('Hello')

    expect(
      getMountedComponent(MyComponent, {
        msg: 'Bye'
      }).text()
    ).toBe('Bye')
  })
})

非同期な更新の検証

Vue は非同期に DOM の更新を行うため、state の変更に対する DOM の更新に関する検証は、Vue.nextTick() が解決した後に行う必要があります。

// state の更新後、生成された HTML の検証を行う
it('updates the rendered message when wrapper.message updates', async () => {
  const wrapper = shallowMount(MyComponent)
  wrapper.setData({ message: 'foo' })

  // state の更新後、DOM の更新をアサートする前に "tick" を待つ
  await wrapper.vm.$nextTick()
  expect(wrapper.text()).toBe('foo')
})

Vue の単体テストに関する詳細情報については、Vue Test Utils とクックブックエントリの Vue コンポーネントの単体テスト について確認してください。