Permalink
Switch branches/tags
Nothing to show
Find file Copy path
741 lines (494 sloc) 27.3 KB

訳注

これはreadme.mdの日本語訳です。こちらがAVAのmasterブランチとの差分のリンクになります(このリンクをクリックして、readme.mdに変更点が見当たらなければ、この翻訳が最新であることを意味します)。


AVA

未来型のテストランナー

Build Status: Linux Build status: Windows Coverage Status Gitter

JavaScript自体はシングルスレッドですが、Node.jsにおけるIOは、その非同期の性質によって並列で実行可能です。AVAは、この事が利点であり、テストを同時に実行することができ、特にIOが重いテストで効果があります。また、テストファイルは独立したプロセスで並列して実行することで、より良いパフォーマンスと各テストファイル毎に分離された環境にすることができます。PageresにおけるMochaからAVAへの切り替えによって、テストにかかる時間を31秒から11秒まで減らしました。並列実行するテストにすると、大域の状態や他のテストの状態から影響を受けないことを意味するようになる粒度が極小のテストを書くようになります。これはすごい事ですよね!

*Issueやプルリクエストなどで貢献したい場合は、コントリビューションガイドを読んでください。

アップデートの情報のためにAVAのTwitterアカウントをフォローしてください。

翻訳: Español, Français, Italiano, 日本語, Português

目次

なぜAVAなのか?

テストの構文

import test from 'ava';

test(t => {
	t.same([1, 2], [1, 2]);
});

使い方

初期設定

AVAを$ npm install --global avaでグローバルにインストールして、$ ava --init(他にどんなオプションでも付けられます)を実行してpackage.jsonにAVAを追加するか手動で作成します。

{
	"name": "awesome-package",
	"scripts": {
		"test": "ava"
	},
	"devDependencies": {
		"ava": "^0.11.0"
	}
}

テストファイルの作成

test.jsという名前のファイルをプロジェクトのルートディレクトリに作ってください。

import test from 'ava';

test('foo', t => {
	t.pass();
});

test('bar', async t => {
	const bar = Promise.resolve('bar');

	t.is(await bar, 'bar');
});

実行

$ npm test

CLIの使い方

$ ava --help

  Usage
    ava [<file|folder|glob> ...]

  Options
    --init           Add AVA to your project
    --fail-fast      Stop after first test failure
    --serial, -s     Run tests serially
    --require, -r    Module to preload (Can be repeated)
    --tap, -t        Generate TAP output
    --verbose, -v    Enable verbose output
    --no-cache       Disable the transpiler cache

  Examples
    ava
    ava test.js test2.js
    ava test-*.js
    ava test
    ava --init
    ava --init foo.js

  Default patterns when no arguments:
  test.js test-*.js test/**/*.js

CLIはグローバルで実行できる場合でも、実行可能であればローカルにインストールされたAVAを実行します。

ディレクトリはデフォルトで再帰的です。fixtureshelpersと名付けられたディレクトリは無視され、_で始まるファイルも同様です。これはテストファイルと同じディレクトリにヘルパーを置くのに役立ちます。

npm testを実行するときに、引数を使ってnpm test test2.jsのようにテストの位置を直接渡すことができます。しかし、フラグはnpm test -- --verboseのように渡す必要があります。

設定

CLIの全てのオプションは、package.jsonavaのセクションで設定できます。この設定でavaコマンドのデフォルトの動作を変更することができるので、同じオプションをコマンドプロンプトで繰り返してタイプする必要がなくなります。

{
  "ava": {
    "files": [
      "my-test-folder/*.js",
      "!**/not-this-file.js"
    ],
    "failFast": true,
    "serial": true,
    "tap": true,
    "verbose": true,
    "require": [
      "babel-core/register"
    ]
  }
}

CLIに渡される引数は常にpackage.jsonの設定よりも優先されます。

ドキュメント

テストは非同期で実行され、サポートされたasyncオブジェクト(promiseかobservable)で返す必要があります。私たちは、async関数を使うことを強く推奨します; これはasyncのコードを簡潔で読みやすいものにして、暗黙のうちにpromiseを返すので、自分では明示的に返す必要はありません。

上記のサポート対象のasyncオブジェクトの中の1つも返さなければ、同期で即座に終了すると考えられます。

promiseかその他のサポート対象のasyncオブジェクトを使用できなければ、test.cb([title], fn)でテストを記述することで"コールバックモード"を有効にできます。この方法で宣言されるテストは、t.end()によって手動で終了しなければなりません。このモードは主にコールバックスタイルのAPIをテストするためのものです。

全てのテストは同期で定義しなければなりません。テストはsetTimeoutsetImmediateなどの中に記述することはできません。

テストのファイルはそれらのカレントディレクトリで実行されるので、process.cwd()は常に__dirnameと同じになります。path.join(__dirname, 'relative/path')とする代わりに相対パスを使用することができます。

テストの解剖

テストをつくるには、AVAからrequireしたtest関数を呼び出して、任意のテスト名とテストの実行する関数を与えます。渡された関数は第1引数としてコンテキストを与えられますが、ここではAVAのメソッドとアサーションを呼び出すことが出来ます。

test('name', t => {
	t.pass();
});

任意のテスト名

テストに名前をつけるのは任意ですが、1つ以上のテストがある場合には名前を使用することを推奨します。

test(t => {
	t.pass();
});

また名前付き関数をテスト名の代わりに選ぶことも出来ます:

test(function name(t) {
	t.pass();
});

アサーションプラン

アサーションプランは特定数のアサーションを確保するのに使用されます。一番よくある状況としては、これでアサーションの期待された数の実行前に終了しなかったテストを確認するような状況です。コールバックやループの中でアサーションがある時に有用なのが、あまりに多くのアサーションが実行されたらテストが失敗することです。注意してほしいのは、AVAはnode-tapやtapeとは違い、計画されたアサーション数に到達しても自動終了はしないという点です。

これは成功するテストになります:

test(t => {
	t.plan(1);

	return Promise.resolve(3).then(n => {
		t.is(n, 3);
	});
});

test.cb(t => {
	t.plan(1);

	someAsyncFunction(() => {
		t.pass();
		t.end();
	});
});

直列テスト

並列実行は素晴らしいものですが、一方で並列で処理できないものもあります。このようなまれなケースでは、並列のテストの前に直列でテストを強制的に実行する、test.serialを呼び出すことができます。

test.serial(t => {
	t.pass();
});

Only-tests

Only-testsはテストを限定的に実行することを強制します。開発時に幾つかのテストだけを実行したいときに役立ちます。

test('will not be run', t => {
	t.fail();
})

test.only('will be run', t => {
	t.pass();
});

Skip-tests

Skip-testsはスキップされたことを出力はしますが、絶対に実行しません。

test.skip('will not be run', t => {
	t.fail();
});

Before & after hooks

setupとteardownの両方または、いずれかが必要なとき、test()と同じように、test.before()test.after()を利用できます。test.before()test.after()に与えられたテスト関数は、全てのテストの前/後で呼び出されます。また各テストにsetup/teardownが必要なときは、test.beforeEach()test.afterEach()が利用できます。必要なだけ追加してください。失敗したときに表示されるタイトルを指定することも必要に応じて出来ます。

test.before(t => {
	// 全てのテストの前に実行します
});

test.before(t => {
	// テストの前に実行しますが、上記の処理の後です
});

test.after('cleanup', t => {
	// 全てのテストの後に実行します
});

test.beforeEach(t => {
	// それぞれのテストの前に実行します
});

test.afterEach(t => {
	// それぞれのテストの後に実行します
});

test(t => {
	// 通常のテスト
});

どのフックでも、asyncを使うこと、asyncオブジェクトを返すこと、"コールバックモード"を有効にすることも、出来ます。

test.before(async t => {
	await promiseFn();
});

test.cb.beforeEach(t => {
	setTimeout(t.end);
});

test.afterEach.cb(t => {
	setTimeout(t.end);
});

test.after(t => {
   return new Promise(/* ... */);
});

beforeEachafterEachのフックは特定のテストでコンテキストを共有できます:

test.beforeEach(t => {
	t.context.data = generateUniqueData();
});

test(t => {
	t.is(t.context.data + 'bar', 'foobar');
});

このコンテキストは、デフォルトでは1つのオブジェクトですが、直接アサインすることも出来ます。

test.beforeEach(t => {
	t.context = 'unicorn';
});

test(t => {
	t.is(t.context, 'unicorn');
});

テスト修飾子のチェーン

テストの修飾子を以下のようにチェーンすることができます。

test.before.skip([title], testFn);
test.skip.after(....);
test.serial.only(...);
test.only.serial(...);

これはテストで、他の修飾子の振る舞いや情報を失わないように一時的にskiponlyを使うときに、特に役立ちます。

カスタムアサーションモジュール

AVAのデフォルトに加えて、または代わりとしてどのようなアサーションモジュールを利用することも可能ですが、今はまだ.plan()メソッドを使うことはできません。

import assert from 'assert';

test(t => {
	assert(true);
});

ES2015のサポート

AVAは、Babel 6を使ってES2015をサポートしています。単にES2015でテストを書いてください。他の環境整備は必要ありません。プロジェクト内でバージョンを問わずにBabelを利用することができます。AVAは、es2015stage-2のプリセットをバンドルしたBabelを使用しています。

importしたモジュールのトランスパイル

現時点でのAVAは、実行するようにしたテストだけをトランスパイルします。*テストの外からimportしたモジュールはトランスパイルしません。*このアプローチを採用したのには妥当な理由がありますが、期待した挙動ではないかもしれません!

シンプルな代替策として、Babel's require hookを使ってインポートされるモジュールをリアルタイムにトランスパイルすることができます。AVAはES2015モジュールをサポートしてるのでrequireフックとして使用ができるからです:

import test from 'ava';
import 'babel-core/register';
import foo from './foo'; // <-- ES2015 で書くことが出来ます!

test('foo bar', t => {
	t.same('baz', foo('bar'));
});

#111が、将来性のある拡張として、議論されています。

Promiseのサポート

テスト中でpromiseを返すと、promiseがresolveしたときに終了するので、明示的にテストを終了する必要はありません。

test(t => {
	return somePromise().then(result => {
		t.is(result, 'unicorn');
	});
});

generator関数のサポート

AVAはgenerator関数をビルトインサポートしています。

test(function * (t) {
	const value = yield generatorFn();
	t.true(value);
});

async関数のサポート

AVAはasync *(async/wait)*をビルトインサポートしています。

test(async function (t) {
	const value = await promiseFn();
	t.true(value);
});

// asyncのアロー関数
test(async t => {
	const value = await promiseFn();
	t.true(value);
});

Observableのサポート

AVAはObservableをビルトインサポートしています。 テストからobservableを返すと、AVAはテストが終了する前にobservableを自動的に完了します。

"コールバックモード"やt.end()は必要ありません

test(t => {
	t.plan(3);
	return Observable.of(1, 2, 3, 4, 5, 6)
		.filter(n => {
			// 偶数のみ
			return n % 2 === 0;
		})
		.map(() => t.pass());
});

コールバックのサポート

AVAはnodeスタイルのエラーファーストのコールバックAPIを使用したときに、最終コールバックとしてt.endの使用をサポートしています。AVAはt.endに渡される第1引数がどんな真と判断される値もエラーと見なします。t.endは、test.cbチェーンを利用することで有効になる、"コールバックモード"が必要になるということを覚えておいてください。

test.cb(t => {
	// t.endは自動的に第1引数としてエラーをチェックします。
	fs.readFile('data.txt', t.end);
});

任意のTAPの出力

AVAは--tapオプションの指定でどのようなTAPレポーターを使用しても、TAPの出力をすることができます。

$ ava --tap | tap-nyan

明快なスタックトレース

エラーの箇所をより素早く見つけられるように、AVAはスタックトレースから自動的に無関係の行を取り除きます。

API

test([title], body)

test.serial([title], body)

test.cb([title], body)

test.only([title], body)

test.skip([title], body)

test.before([title], body)

test.after([title], body)

test.beforeEach([title], body)

test.afterEach([title], body)

title

Type: string

テストのタイトルです。

body(context)

Type: function

実際にテストが含まれている必要があります。

context

テスト関数に渡され、個別のAVAのメソッドとアサーションが含まれます。

.plan(count)

テストの中でいくつのアサーションがあるかを計画します。計画されたアサーションと実際のアサーションの数が一致しない場合、テストは失敗します。

.end()

テストを終了します。test.cb()と一緒に使用しないと動きません。

アサーション

アサーションはテストのコンテキストに合成されています:

test(t => {
	t.ok('unicorn'); // アサーション
});

1つのテストの中で複数のアサーションの失敗が発生したとき、AVAは最初の1つだけを表示します。

.pass([message])

アサーションを通します。

.fail([message])

アサーションを失敗させます。

.ok(value, [message])

valueが真と判断できる値とします。

.notOk(value, [message])

valueが偽と判断できる値とします。

.true(value, [message])

valuetrueであるとします。

.false(value, [message])

valuefalseであるとします。

.is(value, expected, [message])

valueexpectedと同じ値であるとします。

.not(value, expected, [message])

valueexpectedと同じ値ではないとします。

.same(value, expected, [message])

valueexpectedと厳密に同じ値であるとします。

.notSame(value, expected, [message])

valueexpectedと厳密に同じ値ではないとします。

.throws(function|promise, [error, [message]])

エラーを投げるfunctionpromiseのrejectであるとします。

errorは、コンストラクタ、正規表現、エラーメッセージ、バリデーション関数などでも大丈夫です。

.notThrows(function|promise, [message])

errorを投げないfunctionpromiseのresolveであるとします。

.regex(contents, regex, [message])

contentsregexにマッチするとします。

.ifError(error, [message])

errorが偽と判断できる値とします。

アサーションのスキップ

skip修飾子を使うことでどのアサーションもスキップできます。スキップされたアサーションはカウントされるので、計画したアサーションの数を変更する必要はありません。

test(t => {
  t.plan(2);
  t.skip.is(foo(), 5); // スキップするときにplanの数を変更する必要はありません。
  t.is(1, 1);
});

強化されたassert

AVAには、より説明的なアサーションメッセージを与える、power-assertがビルトインとして付属してます。これにより、テストを読んでよりコード内部の情報を得ることができます。

以下のようなテストの場合:

test(t => {
	const x = 'foo';
	t.ok(x === 'bar');
});

この場合、普通はほとんど手助けにならない出力になります:

false === true

強化されたassertでは以下のような結果が得られます:

t.ok(x === 'bar')
     |
     "foo"

実際はこのような場合にはt.is()を使えますし、そうしたほうが良いですが、これはただの簡単な例です。

もっと高度な例を試しましょう:

test(t => {
	const a = /foo/;
	const b = 'bar';
	const c = 'baz';
	t.ok(a.test(b) || b === c);
});

この結果は以下です:

t.ok(a.test(b) || b === c)
       |    |     |     |
       |    "bar" "bar" "baz"
       false

全てのassertのメソッドは強化されています。

楽しんでください!

分離された環境

それぞれのテストファイルは分離されたNode.jsのプロセスで実行されます。これには多くの利点があります。それぞれのテストファイルは互いに影響することはありません。グローバル環境でのテストファイルのモック使用、ビルトインの機能を上書きしたりなどなどです。しかし、主にパフォーマンスの理由によりこうしています。Node.jsは非同期IOを同時に実行できますが、テストがメインスレッドをブロックするような、重い同期処理の場合はあまり役に立ちません。テストを同時に実行して並列でテストすることで、モダンシステムの利点を最大限に活用できます。

Tips

一時ファイル

テストを並列で行うことには色々な問題が伴いますが、IOがその1つです。一般的に、直列のテストではカレントディレクトリに一時的なディレクトリを作成して、終了時にそれを削除します。並列ではテストがお互いに競合するのでこれはできません。正しいやり方としては、それぞれのテストが新規に一時ディレクトリを利用することです。tempfiletemp-writeといったモジュールが役立つでしょう。

デバッグ

AVAはデフォルトで並列にテストを実行しますが、何かデバッグする必要があるときには最善ではありません。代わりに--serialオプションをつけてテストを直列で実行してください:

$ ava --serial

コードカバレッジ

AVAが実行するテストファイルのコードカバレッジにistanbulを使うことは出来ませんが、代わりにサブプロセスのサポートがあるistanbulであるnycを利用できます。

バージョン5.0.0では、トランスパイルに関係なく、実際のコードのカバレッジをレポートするのにソースマップを使います。テスト対象のコードがインラインのソースマップかソースマップファイルへの参照のいずれかを含んでいることを確認してください。babel/registerを使っていれば、.babelrcsourceMapsオプションをinlineに設定できます。

FAQ

なぜmochatapenode-tapではダメなのか?

Mochaはデフォルトのインターフェース(多くの人々が利用している)でdescribeitのような暗黙のグローバルを利用することを必須になっており、強い主張もなく、肥大化していて、デフォルトで同期で、プログラム的なAPIもなくて、直列でテストを実行して、そして遅いです。Tapeやnode-tapはかなり良いです。AVAはそれらのシンタックスに強く影響を受けています。ですが、これらはいずれも、テストを直列で実行し、TAPを第1級オブジェクトとして作り上げ、私の見方ですが、これがコードベースを複雑で結合したものにしました。TAPの出力は読みづらいので、外部のレポーターを利用することになります。AVAは自己主張が強く並列です。デフォルトの簡単なレポーターがあり、CLIのフラグを通じてTAPもサポートしています。

どうやってカスタムレポーターを使いますか?

TAP reporterの中の何でも一つを--tap フラグから使ってください。

名前はどのように書いて、どう発音するのか?

AVAで、Avaやavaではありません。発音は/ˈeɪvə/ ay-vəです。

ヘッダーの背景は何?

アンドロメダ銀河です。

並行 vs. 並列

並行は並列ではありません。それは並列を可能にするものです。

レシピ

サポート

関連リンク

リンク

開発者

Sindre Sorhus | Vadim Demedes | James Talmage ---|---|---|--- Sindre Sorhus | Vadim Demedes | James Talmage

元メンバー




AVA