# ユニットテスト

ユニットテストは、アプリケーション開発の重要な(そして時には無視される)部分です。 プロセスとワークフローを保護するのに役立ち、プロジェクトの最も重要な部分が、開発における偶発的なミスや見落としから確実に保護されます。 Vue には vue-test-utils と呼ばれる独自のテストユーティリティがあります。 Vueコンポーネントとのやり取りに便利な機能を提供し、多くの一般的なテストランナーと連携します。

# テスト ランナー

Vue CLI でテストランナーをセットアップする方法については、 公式ドキュメント を参照してください。 Vue CLIには以下のテストランナーのための getting started リポジトリがあります:

# Vuetifyのブートストラップ

Typescriptを適切に利用するために、VuetifyコンポーネントはVueオブジェクトを拡張します。 これは、上記のアラートに記載されているように、問題を引き起こす可能性があります。 localVueインスタンス を使用する代わりに、ユニットテストのセットアップファイルに Vuetify をグローバルにインストールする必要があります。 これはテストランナーによって異なる場合があります。 セットアップファイルに関する適切なドキュメントを参照してください。

// tests/setup.js

import Vue from 'vue'
import Vuetify from 'vuetify'

Vue.use(Vuetify)

# Spec Tests

Vuetifyでのユニットテストの作成は、 localVue インスタンスでVuetifyオブジェクトを使用し、インスタンスをマウント関数オプションに渡すという点で vuex および vue-router に似ています。 違いは、 Vuetify が localVue インスタンスでは使用されないことです。

// Imports
import AppBtn from '../AppBtn.vue'
import Vuetify from 'vuetify'

// Utilities
import { createLocalVue, mount } from '@vue/test-utils'

describe('AppBtn.vue', () => {
  // DO NOT use Vuetify on the localInstance
  // This is bootstrapped in the jest setup
  // file located in ./tests/setup.js
  //
  // localVue.use(Vuetify)

  const localVue = createLocalVue()
  let vuetify

  beforeEach(() => {
    vuetify = new Vuetify()
  })

  it('should work', () => {
    //
  })
})

アプリケーションで見つかる可能性のあるサンプルテストユースケースを作成しましょう。

<!-- Vue Component -->

<template>
  <v-card>
    <v-card-title>
      <span v-text="title"></span>

      <v-spacer></v-spacer>

      <v-btn @click="$emit('action-btn:clicked')">
        Action
      </v-btn>
    </v-card-title>

    <v-card-text>
      <slot></slot>
    </v-card-text>
  </v-card>
</template>

<script>
  export default {
    props: {
      title: {
        type: String,
        required: true,
      },
    },
  }
</script>

上の例では、 title prop と v-btn をクリックしたときにカスタムイベントを発生させるカスタムコンポーネントを作成しました。 この動作が正しく動作するようにテストを作成し、今後の変更を通じて継続的にテストを行いたいと考えています。 以下の例は Jest のテストランナーで作成されています。

// test/CustomCard.spec.js

// Libraries
import Vuetify from 'vuetify'

// Components
import CustomCard from '@/components/CustomCard'

// Utilities
import { createLocalVue, mount } from '@vue/test-utils'

describe('CustomCard.vue', () => {
  const localVue = createLocalVue()
  let vuetify

  beforeEach(() => {
    vuetify = new Vuetify()
  })

  it('should have a custom title and match snapshot', () => {
    const wrapper = mount(CustomCard, {
      localVue,
      vuetify,
      propsData: { title: 'Foobar' },
    })

    // With jest we can create snapshot files of the HTML output
    expect(wrapper.html()).toMatchSnapshot()

    // We could also verify this differently
    // by checking the text content
    const title = wrapper.find('.v-card__title > span')

    expect(title.text()).toBe('Foobar')
  })

  it('should emit an event when the action v-btn is clicked', () => {
    const wrapper = mount(CustomCard, {
      localVue,
      vuetify,
      propsData: { title: 'Foobar' },
    })

    const event = jest.fn()
    const button = wrapper.find('.v-btn')

    // Here we bind a listener to the wrapper
    // instance to catch our custom event
    // https://vuejs.org/v2/api/#Instance-Methods-Events
    wrapper.vm.$on('action-btn:clicked', event)

    expect(event).toHaveBeenCalledTimes(0)

    // Simulate a click on the button
    button.trigger('click')

    // Ensure that our mock event was called
    expect(event).toHaveBeenCalledTimes(1)
  })
})

# 効率的にテストする

テストを書く場合は、何度も何度も同じことを繰り返すことになります。 この場合、個々のテストの重複を減らすためのヘルパー関数を作成することが有益です。 基本的には、コードを DRYing にします。

単体テストで書かれる最も一般的な重複コードの1つは、マウント機能です。 これは、実行ごとに簡単に再利用可能な機能に圧縮できます。

// test/CustomCard.spec.js

describe('CustomCard.vue', () => {
  const localVue = createLocalVue()
  let vuetify

  beforeEach(() => {
    vuetify = new Vuetify()
  })

  const mountFunction = options => {
    return mount(CustomCard, {
      localVue,
      vuetify,
      ...options,
    })
  }

  it('should have a custom title and match snapshot', () => {
    const wrapper = mountFunction({
      propsData: { title: 'Fizzbuzz' },
    })

    expect(wrapper.html()).toMatchSnapshot()
  })
})

# Vuetify の Mocking

Vuetifyのコンポーネントの多くは、デフォルトテキストやブレークポイント情報などの設定を導出するためにグローバル $vuetify オブジェクトを使用しています。 これらのコンポーネントをテストする場合は、 vue-test-utils にモックオブジェクトを渡す必要があります。

// test/CustomAlert.spec.js

// Libraries
import Vuetify from 'vuetify'

// Components
import CustomAlert from '@/components/CustomAlert'

// Utilities
import { createLocalVue, mount } from '@vue/test-utils'

const localVue = createLocalVue()

describe('CustomAlert.vue', () => {
  let vuetify

  beforeEach(() => {
    vuetify = {
      mocks: {
        $vuetify: {
          lang: {
            t: (val: string) => val,
          },
        },
      }
    }
  })

  it('should have a custom title and match snapshot', () => {
    const wrapper = mount(CustomAlert, {
      localVue,
      vuetify,
    })

    expect(wrapper.html()).toMatchSnapshot()
  })
})

使用されているサービスだけをスタブする必要があることを覚えておいてください (langapplicationのように)。 これらのサービスを手動でインポートすることもできます。

// test/CustomNavigationDrawer.spec.js

// Libraries
import Vuetify from 'vuetify'

// Components
import CustomNavigationDrawer from '@/components/CustomNavigationDrawer'

// Utilities
import {
  createLocalVue,
  mount,
} from '@vue/test-utils'

const localVue = createLocalVue()

describe('CustomNavigationDrawer.vue', () => {
  let vuetify

  beforeEach(() => {
    vuetify = new Vuetify()
  })

  it('should have a custom title and match snapshot', () => {
    const wrapper = mount(CustomNavigationDrawer, {
      localVue,
      vuetify,
    })

    expect(wrapper.html()).toMatchSnapshot()
  })
})

利用可能なサービスは以下のとおりです。

# E2E テスト

Vuetifyは、コンポーネントから関連するHTML要素に data-* 属性を渡します。これにより、E2Eテストフレームワークはそれらの要素を簡単に見つけることができます。

たとえば、Cypress は、要素を簡単にターゲティングできるようにするために data-cy 属性を追加することを推奨しています。

<template>
  <!-- Vuetify component with data-cy -->
  <v-text-field v-model="name" data-cy="name-input" />

  <!-- HTML render output -->
  <input data-cy="name-input" id="input-120" type="text">
</template>
// cypress/integration/test.spec.js

describe('Test With Attribute', () => {
  it('Find by data-cy', () => {
    cy.visit('/')
    cy.get('[data-cy=name-input]').type('Zak')  // data-cyを使った要素の検索
  })
})

準備はできましたか?

Vuetifyのチームが選ぶ関連コンテンツで他の学習トピックに進むか、下のナビゲーション リンクでページ間を移動できます。
GitHub でこのページを編集する
最終更新日:07/05/2022, 9:08:15 PM