はじめに

テスト

AdonisJSにはテストを書くための組み込みサポートがあります。追加のパッケージをインストールしたり、アプリケーションをテストの準備のために設定する必要はありません - すべての重要な作業はすでに完了しています。

次のaceコマンドを使用してアプリケーションのテストを実行できます。

node ace test

テストはtestsディレクトリに格納され、さらにタイプごとにテストが整理されています。たとえば、機能テストはtests/functionalディレクトリに格納され、ユニットテストはtests/unitディレクトリに格納されます。

機能テストは、実際のHTTPリクエストを使用してアプリケーションをテストし、特定のフローやエンドポイントの機能をテストします。たとえば、ユーザーの作成に関する機能テストのコレクションがあるかもしれません。

一部のコミュニティでは、機能テストをフィーチャーテストまたはエンドツーエンドテストと呼ぶこともあります。AdonisJSでは、それらをどのように呼ぶかについて柔軟です。私たちは「機能テスト」という用語を採用することにしました。

テストランナーの設定

AdonisJSは、テストの作成と実行にJapaを使用しています。そのため、Japaのドキュメントを読んでAPIと設定オプションをよりよく理解することをお勧めします。

スイート

テストスイートはadonisrc.tsファイルで定義されます。デフォルトでは、functionalunitのテストスイートが登録されています。必要に応じて、既存のスイートを削除してから新しく作成することができます。

{
tests: {
suites: [
{
name: 'functional',
files: ['tests/functional/**/*.spec.(js|ts)']
},
{
name: 'unit',
files: ['tests/unit/**/*.spec.(js|ts)']
}
]
}
}
  • スイートは、スイートの一意の名前とファイルのグロブパターンを組み合わせたものです。
  • 特定のスイートのテストを実行すると、そのスイートに関連するファイルのみがインポートされます。

tests/bootstrap.tsファイルで定義されたconfigureSuiteフックを使用して、実行時にスイートを設定することもできます。たとえば、機能テストを実行するときに、スイートレベルのフックを登録してHTTPサーバーを起動することができます。

export const configureSuite: Config['configureSuite'] = (suite) => {
if (['browser', 'functional', 'e2e'].includes(suite.name)) {
return suite.setup(() => testUtils.httpServer().start())
}
}

ランナーフック

ランナーフックは、すべてのテストの前後に実行されるグローバルなアクションです。フックはtests/boostrap.tsファイル内のrunnerHooksプロパティを使用して定義されます。

export const runnerHooks: Required<Pick<Config, 'setup' | 'teardown'>> = {
setup: [
() => {
console.log('running before all the tests')
}
],
teardown: [
() => {
console.log('running after all the tests')
}
],
}

プラグイン

Japaには機能を拡張するためのプラグインシステムがあります。プラグインはtests/bootstrap.tsファイルに登録されます。

参考: Japaプラグインの作成

export const plugins: Config['plugins'] = [
assert(),
pluginAdonisJS(app)
]

レポーター

レポーターは、テストの進行状況を報告/表示するために使用されます。レポーターはtests/bootstrap.tsファイルに登録されます。

参考: Japaレポーターの作成

export const reporters: Config['reporters'] = {
activated: ['spec']
}

テストの作成

make:testコマンドを使用して新しいテストを作成できます。コマンドにはスイートの名前が必要です。

参考: テスト作成コマンド

node ace make:test posts/create --suite=functional

ファイルはfilesグロブプロパティで設定されたディレクトリ内に作成されます。

テストの記述

テストは@japa/runnerパッケージからインポートされたtestメソッドを使用して定義されます。テストは、最初のパラメータとしてタイトル、2番目のパラメータとして実装のコールバックを受け入れます。

次の例では、新しいユーザーアカウントを作成し、assertオブジェクトを使用してパスワードが正しくハッシュ化されていることを確認しています。

import { test } from '@japa/runner'
import User from '#models/User'
import hash from '@adonisjs/core/services/hash'
test('新しいユーザーを作成するときにユーザーパスワードをハッシュ化する', async ({ assert }) => {
const user = new User()
user.password = 'secret'
await user.save()
assert.isTrue(hash.isValidHash(user.password))
assert.isTrue(await hash.verify(user.password, 'secret'))
})

テストグループの使用

テストグループはtest.groupメソッドを使用して作成されます。グループはテストに構造を追加し、テストの周りでlifecycle hooksを実行することができます。

前の例を続けて、パスワードのハッシュ化テストをグループ内に移動させましょう。

import { test } from '@japa/runner'
import User from '#models/User'
import hash from '@adonisjs/core/services/hash'
test.group('ユーザーの作成', () => {
test('ユーザーパスワードをハッシュ化する', async ({ assert }) => {
const user = new User()
user.password = 'secret'
await user.save()
assert.isTrue(hash.isValidHash(user.password))
assert.isTrue(await hash.verify(user.password, 'secret'))
})
})

気づいたかもしれませんが、テストタイトルから「新しいユーザーを作成するとき」のフラグメントを削除しました。これは、グループのタイトルがこのグループのすべてのテストが「新しいユーザーの作成」に関連していることを明確にしているためです。

ライフサイクルフック

ライフサイクルフックは、テストの周りでアクションを実行するために使用されます。フックはgroupオブジェクトを使用して定義することができます。

参考 - ライフサイクルフックのJapaドキュメント

test.group('ユーザーの作成', (group) => {
group.each.setup(async () => {
console.log('すべてのテストの前に実行されます')
})
group.each.teardown(async () => {
console.log('すべてのテストの後に実行されます')
})
group.setup(async () => {
console.log('すべてのテストの前に一度だけ実行されます')
})
group.teardown(async () => {
console.log('すべてのテストの後に一度だけ実行されます')
})
test('ユーザーパスワードをハッシュ化する', async ({ assert }) => {
const user = new User()
user.password = 'secret'
await user.save()
assert.isTrue(hash.isValidHash(user.password))
assert.isTrue(await hash.verify(user.password, 'secret'))
})
})

次のステップ

テストの作成と記述の基本を学んだので、Japaドキュメントで以下のトピックを探索することをお勧めします。

テストの実行

testコマンドを使用してテストを実行できます。デフォルトでは、すべてのスイートのテストが実行されます。ただし、名前を渡すことで特定のスイートのテストを実行することもできます。

node ace test
node ace test functional
node ace test unit

ファイルの変更を監視してテストを再実行する

--watchコマンドを使用してファイルシステムを監視し、テストを再実行することができます。テストファイルが変更された場合、変更されたファイル内のテストが実行されます。それ以外の場合は、すべてのテストが再実行されます。

node ace test --watch

テストのフィルタリング

テストを実行する際にコマンドラインフラグを使用してフィルタを適用することができます。以下に利用可能なオプションのリストを示します。

参考: Japaテストのフィルタリングガイド

VSCodeを使用していますか? キーボードショートカットやアクティビティサイドバーを使用して、コードエディタ内で選択したテストを実行するためにJapa拡張機能を使用できます。

フラグ説明
--testsテストタイトルでテストをフィルタリングします。このフィルタは、完全なテストタイトルに一致します。
--filesテストファイル名の一部でテストをフィルタリングします。マッチは、.spec.tsを除いたファイル名の末尾で行われます。ワイルドカード式を使用して、完全なフォルダのテストを実行することもできます。 folder/*
--groupsグループ名でテストをフィルタリングします。このフィルタは、完全なグループ名に一致します。
--tagsタグでテストをフィルタリングします。タグ名の前にチルダ~を付けると、指定したタグを持つテストを無視します。
--matchAllデフォルトでは、Japaは指定されたタグに一致するテストを実行します。すべてのタグを一致させたい場合は、--matchAllフラグを使用します。

テストの強制終了

Japaは、すべてのテストが完了した後、プロセスが正常にシャットダウンするのを待ちます。正常なシャットダウンプロセスとは、すべての長寿命の接続を終了し、Node.jsのイベントループを空にすることを意味します。

必要に応じて、--force-exitフラグを使用してJapaにプロセスを終了させ、正常なシャットダウンを待たないようにすることができます。

node ace test --force-exit

テストのリトライ

--retriesフラグを使用して、複数回の失敗したテストをリトライすることができます。このフラグは、テストレベルで明示的なリトライ回数が定義されていないすべてのテストに適用されます。

# 失敗したテストを2回リトライする
node ace test --retries=2

前回の実行からの失敗したテストの実行

--failedコマンドラインフラグを使用して、前回の実行から失敗したテストを再実行することができます。

node ace test --failed

レポーターの切り替え

Japaでは、複数のテストレポーターを設定ファイルに登録することができますが、デフォルトではそれらはアクティブ化されません。レポーターをアクティブ化するには、設定ファイル内または--reporterコマンドラインフラグを使用します。

# specレポーターをアクティブ化する
node ace test --reporter=spec
# specとjsonレポーターをアクティブ化する
node ace test --reporter=spec,json

設定ファイル内でもレポーターをアクティブ化することができます。

export const reporters: Config['reporters'] = {
activated: ['spec', 'json']
}

Node.jsコマンドラインにオプションを渡す

testコマンドは、(bin/test.ts file)を子プロセスとして実行します。子プロセスにnode引数を渡す場合は、コマンド名の前にそれらを定義することができます。

node ace --no-warnings --trace-exit test

環境変数

テスト中に必要な環境変数を定義するために、.env.testファイルを使用することができます。.envファイル内の値よりも.env.test内の値が優先されます。

テスト中のSESSION_DRIVERmemoryに設定する必要があります。

.env.test
SESSION_DRIVER=memory