29
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

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:

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
29
Help us understand the problem. What are the problem?