Edited at
Vue.jsDay 17

JestでプレーンJS/Vue.jsのTDDを行う

fukuoka.ex代表のpiacereです

ご覧いただいて、ありがとうございます:bow:

JavaScriptのテスティングフレームワーク「Jest」を使って、プレーンJSとVue.jsのテストを行ってみます

TDD(Test Driven Development)の流れで実施していきます


npmのインストール

npmを利用可能にするため、下記から適宜Node.jsをインストールしてください

https://nodejs.org/ja/download/


package.jsonを作成

適当なフォルダを掘って、その配下に、下記ファイルを作成します


package.json

{

"scripts":
{
"test": "jest"
}
}


Jestのインストール

package.jsonを作ったフォルダ配下に移動し、シェル/コマンドプロンプトで、以下コマンドを実行します


シェル/コマンドプロンプト

npm install --save-dev jest


(なお、npmの代わりにyarnを使ってもOKですが、ここでは解説は割愛するので、分かる方だけ自己解決してください)


テストを作成

TDDをするので、まずテストを作成します

expect()に実測値(actual)を入れ、それをtoBe()で期待値(expected)と比較することで、「assertEquals」のような動きになります

Jestでのテストファイルは、ファイル名に「test」もしくは「spec」を入れると、テスト実行対象になります

テスト対象メソッドとして、add()という、足し算を行うメソッドを想定します(ただし、TDDするので、この時点ではロジック自体を作りません)


sample.test.js

test( '1 + 2 = 3', () => 

{
expect( add( 1, 2 ) ).toBe( 3 )
} )


テストを実行(Redパターン)

以下コマンドでテストを実行します


シェル/コマンドプロンプト

npm test


ロジックが無いので、当然、まっ赤っかのテスト失敗(Red)になります

image.png


ロジックを追加し、テストを実行(Greenパターン)

ロジックを実装します(現在のテストを通す、最も小さい実装を行います)

なお、module.exportsで指定するのは、メソッド名です


sample.js

function add( a, b )

{
return 3;
}
module.exports = add;

TDDに慣れていない方だと、「いやいや、そんなロジック作らないでしょ」と言いそうですが、より複雑なケースや、ロジックの組み合わせをする中で、「現在、詳細に実装しなくても、取り敢えずの値を返してくれればOK」というシチュエーションは、案外あります

そういう場合、上記のような、ダミー実装をして、その他の実装を進めるパターンも往々にしてあります(流石にここまで簡単だと「実装しようよ」となりますけど、あくまで実装し切らない状況もある、というTDDの例です)

テスト側も、実装を呼べるよう、requireを追加します


sample.test.js

const add = require( './sample' )

test( 'add', () =>
{
expect( add( 1, 2 ) ).toBe( 3 )
} )


改めて、テストを実行します


シェル/コマンドプロンプト

npm test


テストが成功し、緑(Green)になりました

image.png


テスト追加でRedになり、ロジック改修(Refactoringパターン)

テストを追加します


sample.test.js

const add = require( './sample' )

test( 'add', () =>
{
expect( add( 1, 2 ) ).toBe( 3 )
expect( add( 2, 3 ) ).toBe( 5 )
} )


改めて、テストを実行します


シェル/コマンドプロンプト

npm test


追加したテスト部分がテスト失敗となります

image.png

ロジックをリファクタリングします


sample.js

function add( a, b )

{
return a + b;
}
module.exports = add;

改めて、テストを実行します


シェル/コマンドプロンプト

npm test


テスト成功しました

image.png

なお、2ケースのテストを実施していますが、実行結果には、「1 passed」と出ているので、これを2ケースにしたい場合は、以下のようにテストメソッドを別々にします


sample.test.js

const add = require( './sample' )

test( 'add 3', () =>
{
expect( add( 1, 2 ) ).toBe( 3 )
} )

test( 'add 5', () =>
{
expect( add( 2, 3 ) ).toBe( 5 )
} )


こうすると、「Tests」が「2 passed」になります

image.png


参考:テストを通す最低限の実装とは?

ちなみに、「テストを通す最低限の実装」という観点だと、実は、こんな実装もあり得ます


sample.js

function add( a, b )

{
return a == 1 ? 3 : 5;
}
module.exports = add;

「なんだこりゃ?」という実装に見えますが、こういう発想を通して、「最低限のロジック実装」とは何なのか、を考える思考プロセスは、とても大事です

この感覚が分からないと、ムダに汎用性が高い、とか、やたらロバストなロジックを、「本当に必要となる前に」書いてしまい、改修やエンハンスがやりにくくなったり、延々と使いもしないロジックをメンテナンスする…といった罠にハマります

こうした、「技術的負債」を作らないための考え方が、TDD/アジャイル開発の始祖である「eXtreme Programming」では、「YAGNI(You ain't gonna need it)」という原則として挙げられています


Vue.jsのメソッドをテストする(Redパターン)

ここまでは、プレーンJSのテストだったので、今度は、Vue.jsのメソッドをテストします

まず、JestでVue.jsを使えるようにします


シェル/コマンドプロンプト

npm add vue jest


同フォルダ配下にテストを追加します


vue_sample.test.js

const app = require( './vue_sample' )

test( 'vue_add 3', () =>
{
expect( app.vue_add( 1, 2 ) ).toBe( 3 )
} )

test( 'vue_add 5', () =>
{
expect( app.vue_add( 2, 3 ) ).toBe( 5 )
} )


中身が空のvue_sample.jsも作っておきます


vue_sample.js


テストを実行すると、プレーンJS用とVue.js用の両方のテストが走ります


シェル/コマンドプロンプト

npm test


プレーンJS用テストは成功し、Vue.js用テストはロジック未実装のため失敗します

image.png


Vue.jsのメソッドを追加し、テストする(Greenパターン)

普通のWebページに適用するのと同じようなVue.jsでロジックを実装します(リファクタリングはしないパターンで行きます)


vue_sample.js

const Vue = require( 'vue' )

var app = new Vue
( {
el: '#app',
data:
{
},
methods:
{
vue_add: function( a, b )
{
return a + b
},
},
} )
module.exports = app


テストを実行します


シェル/コマンドプロンプト

npm test


テストは成功しますが、「#app」は未定義のため、warningが出ています

image.png

気になるときは、el部をコメントアウト(もしくはコンポーネント化)してください


vue_sample.js



var app = new Vue
( {
// el: '#app',
data:


image.png


補足:axiosでのAPI呼出をテストする際の注意点

Vue.jsで、API呼出に利用する「axios」のテストを書く際は、前段でJestにaxiosを導入します


シェル/コマンドプロンプト

npm add axios jest


また、非同期呼出のままだと、テスト実施時のexpectで空振りとなるため、async/awaitの付け忘れに注意してください


axios_sample.test.js

const axios = require( 'axios' )

test( 'axios_get', async () =>
{
var results = []
await axios.get( 'https://qiita.com/api/v2/items?query=elixir' )
.then( response => { results = response.data } )

expect( results.length ).toBe( 20 )
} )



終わり

こんな感じで、Jestを使うと、気軽にプレーンJSも、Vue.jsも、TDDしていけます

なお、Jest自体は、特にJSフレームワークを選ぶものでは無い、JavaScriptであれば使えるテスティングフレームワークですので、ReactやAngularをお使いの方でもトライしてみてください


p.s.「いいね」よろしくお願いします

ページ左上の image.pngimage.png のクリックを、どうぞよろしくお願いします:bow:

ここの数字が増えると、書き手としては「ウケている」という感覚が得られ、連載を更に進化させていくモチベーションになりますので、もっとElixirネタを見たいというあなた、私達と一緒に盛り上げてください!:tada: