65
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Vue.jsAdvent Calendar 2016

Day 16

axiosを利用したVue componentのUnitTest

Last updated at Posted at 2016-12-16

本記事は Vue.js Advent Calendar 2016の16日目の記事となります。よろしくお願いします。

始めに

先日「Vue.js componentでvue-router,vue-resourceを利用したメソッドのUnitTestを書く方法」というのを書きましたが、vue-resourceはVue.js本家から引退したこともあり、HTTP Clientをaxiosに乗り換えてみました。

今回はaxiosを利用したVue componentのUnit Testを書く方法をまとめます。また今回のサンプルコードは全てこちらにあります。

環境

下記を利用します。テスト環境は Karma + mocha + chai + sinonですが、これらの説明は今回は省略します。

テストケース

テスト対象コード

下記のようにaxios.getを利用し 仮のGETエントリポイント/items からアイテム一覧を取得する例とします。

// test.vue
<script>
import axios from 'axios';
export default {
  data: () => {
    return {
      items: []
    }
  },
  methods: {
    fetchItems() {
      axios.get('/items').then((response) => {
        this.items = response.data;
      }).catch((response) => {
      });
    }
  }
}
</script>

上記のようなaxios.getは非同期処理となるため少し工夫が必要です。

準備

今回のテストを書くためには以下が必要となります。

  • sinon
    • axios.get をスタブ化するために必要です
  • bluebird
    • テストコード内で Promise オブジェクトを扱うために必要。これが無いと Can't find variable: Promise.と言われてしまう。

ステップ1:サブクラスの作成

  • テストに必要な各種ライブラリを読み込みます
  • テスト対象となるコンポーネントをテストするにはインスタンス化させる必要があるので、 Vue.extend を利用してサブクラスを作成します。
import Vue from 'vue';
import _Test from '../../test.vue';
import sinon from 'sinon';
import axios from 'axios';
import Promise from 'bluebird';

const Test = Vue.extend(_Test);

ステップ2:テストケースを作る

  • 次にdescriptとitでテストケースを作成します。ここでのポイントは今回は非同期のテストなので仮引数に done を記述します。これはmochaの仕様で done() を実行することでmochaにテストが終了したことを通知します。
describe('Testコンポーネント', () => {
  it('fetchItemsでアイテム一覧が取得できる', (done) => {
    // ここにテストコードを書きます
  })
})

ステップ3:axios.getのスタブ化

  • まずは返り値を作成します。今回は成功ケースとするので new Promise.resolve() を変数に入れます。その際に引数としてレスポンスとして返す値を設定しておきます。
  • メソッドのスタブ化は var stub = sinon.stub(object, "method", func); の形式で出来ます。また returns で今回の返り値を設定します。
  • Stub API
    let items = [
      { name: 'Apple' }
    ];

    let resolved = new Promise.resolve({
      data: items
    })

    let stub = sinon.stub(axios, 'get').returns(resolved)

アサーション

  • まずはステップ1で作成したサブクラスをインスタンス化しテスト対象メソッドを実行します。axios.get はスタブ化済みなのでAPIは実行されません。
  • 先ほど作成した Promise オブジェクトの .then を利用してわざと成功ケースに入ります。この中でアサーションをします。
  • そして最後に done() を実行することでmochaにテストが終了したことを通知して終了です。
    const vm = new Test()
    vm.fetchItems();

    resolved.then(() => {
      expect(vm.items).to.be.eql(items)
      done()
    });

テストコードの完成品は以下となります。

import Vue from 'vue';
import _Test from '../../test.vue';
import sinon from 'sinon';
import axios from 'axios';
import Promise from 'bluebird';

const Test = Vue.extend(_Test);

describe('Testコンポーネント', () => {

  it('fetchItemsでアイテム一覧が取得できる', (done) => {
    let items = [
      { name: 'Apple' }
    ];

    let resolved = new Promise.resolve({
      data: items
    })

    let stub = sinon.stub(axios, 'get').returns(resolved)

    const vm = new Test()
    vm.fetchItems();

    resolved.then(() => {
      expect(vm.items).to.be.eql(items)
      done()
    }).catch(done);

  })
})

実行結果

以下は実行結果で正常に通ります。

# 中身はkarma start karma.conf.jsです
$ npm run test

> axios-unit-test@ test 
> karma start karma.conf.js

04 12 2016 19:25:43.713:INFO [framework.browserify]: bundle built
04 12 2016 19:25:43.725:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
04 12 2016 19:25:43.726:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
04 12 2016 19:25:43.735:INFO [launcher]: Starting browser PhantomJS
04 12 2016 19:25:44.564:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket /#G2ampAa8GMejBizyAAAA with id 33009121

  Testコンポーネント
    ✓ fetchItemsでアイテム一覧が取得できる

PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 1 of 1 SUCCESS (0.012 secs / 0.012 secs)
TOTAL: 1 SUCCESS

まとめ

後半になって気づいたんですが、書いている内容はほぼブログに書いた記事と同じでした・・・。ただ前回と違うのは今回はaxiosであり、前回のようなグローバル関数ではないので調整方法が変わりました。これはこれで成功ケースのテストを通すのに数日かかりましたので、その成果としてまとめました。何らかの参考になれば幸いです。

明日は @ponkotuyさん です。

65
43
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
65
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?