本記事は 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さん です。