"BOKU"のITな日常

還暦越えの文系システムエンジニアの”BOKU”は新しいことが大好きです。

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

JavaScriptのテストフレームワークの「ava」の使い方を簡単に整理してみます。

f:id:arakan_no_boku:20190526162551p:plain

 

今回の前提とかもろもろ

 

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

自分がavaを気に入っている理由は「シンプルでわかりやすい」ことにつきます。

普通にJavaScriptの関数をテストするなら、快適で、悩むところも少ないです。

なんですが。

Nuxtと組合せて、自前で作ったモジュールやプラグインをUNITテストしていく部分で、まだ、自分は試行錯誤中です。

Nuxt.jsのドキュメントにも「e2eテスト」のサンプルとかを参考に、あーだ・こーだしてますが、まだ納得いく感じになりません。

ja.nuxtjs.org

 

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

 

インストールなど

 

上記の事情からNuxt.jsのテストは、今回はないのですけど、動作確認した環境は、テストフレームワークとして「ava」を選択したものです。

以下の手順でインストールしています。

arakan-pgm-ai.hatenablog.com

追加で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

 

上記を、ざっと、簡単に使ってみたサンプル

 

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

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);
})

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

 

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ケースです。 

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

ではでは。