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

[fukuoka.ex](https://fukuokaex.connpass.com/)代表のpiacereです
ご覧いただいて、ありがとうございます:bow:

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

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

# npmのインストール

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

# package.jsonを作成

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

```javascript:package.json
{
	"scripts": 
	{
		"test": "jest"
	}
}
```

# Jestのインストール

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

```sh:シェル／コマンドプロンプト
npm install --save-dev jest
```

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

# テストを作成

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

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

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

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

```javascript:sample.test.js
test( '1 + 2 = 3', () => 
{
	expect( add( 1, 2 ) ).toBe( 3 )
} )
```

# テストを実行（Redパターン）

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

```sh:シェル／コマンドプロンプト
npm test
```

ロジックが無いので、当然、まっ赤っかのテスト失敗（Red）になります
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/a0d8c312-bf06-f358-cfb9-0a7fd7ba3d26.png)

# ロジックを追加し、テストを実行（Greenパターン）

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

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

```javascript:sample.js
function add( a, b )
{
	return 3;
}
module.exports = add;
```

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

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

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

```javascript:sample.test.js
const add = require( './sample' )

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

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

```sh:シェル／コマンドプロンプト
npm test
```

テストが成功し、緑（Green）になりました
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/470b7a43-0a57-77bc-20ea-7e7a341704bc.png)

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

テストを追加します

```javascript:sample.test.js
const add = require( './sample' )

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

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

```sh:シェル／コマンドプロンプト
npm test
```

追加したテスト部分がテスト失敗となります
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/9e0a107f-f94c-e821-474e-a01a1bed8597.png)

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

```javascript:sample.js
function add( a, b )
{
	return a + b;
}
module.exports = add;
```

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

```sh:シェル／コマンドプロンプト
npm test
```

テスト成功しました
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/ed737ddf-2f82-088b-4b93-e84f4d1e18ba.png)

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

```javascript: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](https://qiita-image-store.s3.amazonaws.com/0/155423/092dbb2d-2026-7634-f2b2-9fdbe8eb77dc.png)

# 参考：テストを通す最低限の実装とは？

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

```javascript: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を使えるようにします

```sh:シェル／コマンドプロンプト
npm add vue jest
```

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

```javascript: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も作っておきます

```javascript:vue_sample.js
```

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

```sh:シェル／コマンドプロンプト
npm test
```

プレーンJS用テストは成功し、Vue.js用テストはロジック未実装のため失敗します
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/fff2ddc0-3f55-0625-a19b-13d26f630d2b.png)

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

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

```javascript: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
```

テストを実行します

```sh:シェル／コマンドプロンプト
npm test
```

テストは成功しますが、「#app」は未定義のため、warningが出ています
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/22799f65-48f6-24e2-7fa9-fc7a898fb508.png)

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

```javascript:vue_sample.js
…
var app = new Vue
( {
//	el: '#app',
	data: 
…
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/2266704c-9784-5fe7-5515-552c3a9fadee.png)

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

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

```sh:シェル／コマンドプロンプト
npm add axios jest
```

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

```javascript: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.png](https://qiita-image-store.s3.amazonaws.com/0/155423/4d515047-cc48-382e-c2b1-3ad0cc50dbbf.png) や ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/a4e3da58-70a3-4197-95a2-6a6906650d01.png) のクリックを、どうぞよろしくお願いします:bow:
ここの数字が増えると、書き手としては「ウケている」という感覚が得られ、連載を更に進化させていくモチベーションになりますので、もっとElixirネタを見たいというあなた、私達と一緒に盛り上げてください！:tada: