SE_BOKUのまとめノート的ブログ

SE_BOKUが知ってること・勉強したこと・考えたことetc

JavaScriptのテストフレームワーク「ava」の基本的な使い方をまとめてみる。

f:id:arakan_no_boku:20190526162551p:plain
目次

はじめに

リライトして目次を追加しました。

内容は2019年5月当時のままです。

僕がNuxt.jsの各機能を理解するために、ひとつひとつ確認したことをまとめていこうと考えています。

インストール・環境構築は、以下の手順でできている前提です。

arakan-pgm-ai.hatenablog.com

Nuxt.jsを整理する方針

Nuxt.js関連資料やサンプルソースを見ると混乱することが多いのは、Nuxt.jsはVue.jsの機能を包含していて、ひとつのソースの中で、どれがNuxt.js特有の機能で、どれがVue.jsの機能かの区別がつけにくいからだと感じています。

その混在しているイメージを図にしてみると、こんな感じに見えます。

f:id:arakan_no_boku:20190511100242p:plain

なので、僕はアプローチとして、各技術要素にわけて、一回に少しずつ要素を確認していくことにしました。

分け方としては、以下のようになると考えています。

  1. Nuxt.js独自の要素ー基本
  2. Vue.js独自の要素
  3. BulmaのCSS要素(Burfyのclassは、Bulmaを使っている場合が多い)
  4. Buefy独自の要素
  5. Nuxt.js独自の要素ー応用
  6. テストフレームワーク他モジュールの要素

今回は、テストフレームワーク他モジュールの要素の部分です。

環境構築時に、テストフレームワークで選択した「ava」について整理します。

JavaScriptのテストフレームワーク「ava」

avaは、JavaScript用のテストフレームワークです。

一応、流れからいけbな、Nuxtと組合せて、自前で作ったモジュールやプラグインをUNITテストしていくサンプルをやったほうがいいのですけど、正直なところ、Nuxt.jsのドキュメントの「e2eテスト」のサンプルとかを参考に、あーだ・こーだしてますが、まだ納得いく感じになりません。

ja.nuxtjs.org

なので、今回はとりあえず「ava」の基本的な使い方だけを整理する感じになります。

すいません。

インストール

追加でavaだけ入れるなら以下を参考にしてください。

npm install --save-dev ava

package.jsonのscriptsに、avaを追加。

"scripts": {
    "test": "ava",
},

です。

基本的な使い方(パターン)

単純なテストを描くだけなら・・という前提ですが。

構文的には、以下の基本形を2つ覚えておけば、ほぼいけます。

同期処理と非同期処理の場合です。

import test from 'ava'

test('通常処理動作確認',t=>{
    t.pass()
})

test('非同期処理動作確認', async t=>{
    const hoge = Promise.resolve('hoge')
    t.is(await hoge, 'hoge')
})

ファイルは.jsファイルとして保存します。

必ず、プロジェクトフォルダの「test」フォルダ以下に配置します。

テストの実行は、以下のコマンドで行います。

npm test

実行すると、testフォルダ以下のjsファイルを再帰的にサブフォルダ以下のものも含めてすべて実行してくれます。

ファイルひとつだけ実行したい場合は

npm test .\test\sample001.js

みたいに、ファイルを直接指定します。

1ファイル内に複数のテストを書いても構いません。

ただ、以下の注意点があります。

  • testのメッセージ欄(上記だと「通常処理動作確認」等書いている部分)の重複はエラーになります。
  • テストファイルの中に実行対象のtest()は最低ひとつ必要で、ない場合はNo tests found エラーになります。
  • testフォルダ以下のjsファイルはみんな処理対象にしてしまうので、ファイルごとテスト対象からはずしたい場合は、xxx.js.orgみたいに拡張子を変えておきます。
テストの実行制御

テストを実行するにあたっての前処理や後処理、および、1ファイル内で処理

をスキップするテストを指定する・・などの実行制御は以下のようなことができます。

実行制御 書き方

ファイルの中でこのテストだけ実行する。

ついていないテストは実行しない。

test.only

ファイルの中でこのテストはスキップする。

ついていないテストだけを実行する。

test.skip

必ず優先的に実行すべきテストを指定する。

非同期の場合でも優先される。

test.serial

テストの実行前処理。

ファイルのテスト全体で1回だけ実行される。

test.before

テストの実行後処理。

ファイルのテストすべてが成功した時にのみ1回だけ実行される。

test.after

テストの実行後処理。

テストが失敗しても実行するようにalwaysをつける。

test.after.always

テストの実行前処理。

ファイルの各テスト毎に実行される。

test.beforeEach

ファイルの各テスト毎に実行される後処理。

テストが失敗なら実行されない

test.afterEach

ファイルの各テスト毎に実行される後処理。

ファイルの各テスト毎に必ず実行される後処理。

test.afterEach.always
必ず優先的に実行すべきテストを指定する test.serial

使い方の例です。

import test from 'ava'

test.before('前処理', t =>{
    console.log('前処理')
})

test('通常処理2',t=>{
    t.pass()
})

test.after('後処理', t =>{
    console.log('後処理')
})

上記のように、testの後ろに追加するだけで、後の書き方は同じです。

アサーション

avaで利用可能なアサーションです。

よく使うものをリストします。

意味 assert
無条件に成功とする。 t.pass()
無条件に失敗とする。 t.fail()

aの結果'がbが等しい時に成功。

aには関数もはいります。

t.is(a,b)

aの結果がbに等しくない時に成功。

aには関数もはいります。

t.not(a,b)

結果がtrueの場合に成功。

右例の場合、aがbより大きい時に成功。

t.true(a > b)

結果がfalseの場合に成功。

右例の場合、aがbより大きくない時に成功

t.false(a > b)

結果aがfalsyな値

(false, 0, "", null, undefined, NaN)

以外の時に成功

t.truthy(a)

結果aがfalsyな値

(false, 0, "", null, undefined, NaN)

である時に成功

t.falsy(a)

結果aとbが等しい時に成功。

JSON・配列型とかの場合。

t.deepEqual(a,b)

結果aとbが等しくない時に成功。

JSON・配列型とかの場合。

t.notDeepEqual(a,b)

aの結果が正規表現bに一致する場合に成功。

aには関数もはいります。

t.regex(a,b)

aの結果が正規表現bに一致しない場合に成功。

aには関数もはいります。

t.notRegex(a,b)

aの結果がで例外が発生していれば成功。

aには関数もはいります。

t.throws(a)

aの結果が例外が発生しなければ成功。

aには関数もはいります。

t.notThrows(a)

なお、上記の「a」の部分にプラグインの関数を使ってテストする場合は、 nuxt.config.jsへの登録等設定は必要ですので、念のため。

上記表以外のものは、こちらのページを参照ください。

github.com

テストサンプル1

みんな、テストをパスするようにしてます。

import test from 'ava'

function ret1(){
    return 'abc'
}

function ret2(){
    return 'a' == 'a'
}

function ret3(){
    return [1,2,3,4,5]
}

function ret4(){
    return NaN
}

function ret5(){
    return {a:1,b:2}
}

function ret6(){
    return '1234567'
}

const ret7 = () => {
	throw new TypeError('error');
};

test('1', t =>{
    t.is(ret1(),'abc')
})

test('2',t=>{
    t.true(ret2())
})

test('3', t =>{
    t.deepEqual(ret3(),[1,2,3,4,5])
})

test('4', t =>{
    t.falsy(ret4())
})

test('5', t =>{
    t.notDeepEqual(ret5(),{a:2,b:2})
})

test('6', t =>{
    t.regex(ret6(),/\d/)
})

test('7', t =>{
    t.throws(() => {
		ret7();
	}, TypeError);
})

雰囲気だけは、わかるかと・・。 

 

テストサンプル2:import/exportを使うパターン

これも雰囲気だけですが,以下のようなJSファイルを作ってやってみます。

まず、exportする側から。

modulesフォルダにtoys.js という名前で保存します。

export default class Toys {
    constructor(a){
        this.x =a
    }

    toTest(){
        return this.x
    }
}

export function sample() {
    return 'abcdef'
}

exportの仕方で受け方が変わるくらいのことなのですが。 

今度は、さっきのファイルをimportして使う側です。

import test from 'ava'
import toys,{sample} from '../modules/toys.js'

test('郵便番号API',t=>{
    const d = new toys(6696)
    t.is(d.toTest(),6696)
    t.is(sample(),'abcdef')
})

これもOKケースです。 

とりあえず、こんな感じですかね。  

ではでは。