0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AdonisJS(アドニスJS)でユニットテストをやってみた

Posted at

はじめに

今までテストコードを書いたことがほとんどなかったのですが、テストコードを書く機会があったので調べながら実装してみました。

今回は、AdonisJSでユニットテストを書いてみます。
AdonisJSって何?って思った方はこちらの記事を読んでいただければと思います:smile:

テストは基本的に以下の3つに分かれます

  • ユニットテスト
  • インテグレーションテスト
  • 機能テスト(フィーチャーテスト、E2Eテストともいう)

やってみた

では、さっそくやってみます!
AdonisJSでは、JapaというNode.js用のテストフレームワークを使用します。

テストの設定

まず、テストをするための設定からです。
adonisrc.tsでユニットテストと機能テストで、どのディレクトリ内のファイルのテストを実行するか定義出来ます。

adonisrc.ts
  tests: {
    suites: [
      {
        files: ['tests/unit/**/*.spec(.ts|.js)'],
        name: 'unit',
        timeout: 2000,
      },
      {
        files: ['tests/functional/**/*.spec(.ts|.js)'],
        name: 'functional',
        timeout: 30000,
      },
    ],
    forceExit: false,
  },

tests/bootstrap.tsで、

  • configureSuite:テスト実行時に行うsuiteレベルのフック
  • runnerHooks:全てのテスト前後でグローバルに行うアクション
  • reporters:テストの進行状況を報告/表示
    を設定できます。
tests/bootstrap.ts
export const configureSuite: Config['configureSuite'] = (suite) => {
  if (['browser', 'functional', 'e2e'].includes(suite.name)) {
    return suite.setup(() => testUtils.httpServer().start())
  }
}

export const runnerHooks: Required<Pick<Config, 'setup' | 'teardown'>> = {
  setup: [
    () => {
      console.log('test start')
    }
  ],
  teardown: [
    () => {
      console.log('test end')
    }
  ],
}

export const reporters: Config['reporters'] = {
  activated: ['spec'] // spec, dot, ndjson, githubを設定できる
}

テストコードを書いてみる

今回は以下のバリデーションクラスのユニットテストを書いてみます。

AdministratorValidator.ts
import vine from '@vinejs/vine'

const common = {
  username: vine.string().trim().minLength(6).maxLength(63).alphaNumeric({
    allowDashes: true,
    allowSpaces: false,
    allowUnderscores: false,
  }),
  password: vine.string().trim().minLength(8).maxLength(32),
  name: vine.string().trim().minLength(6).maxLength(127),
  roleId: vine.string().uuid(),
}

/**
 * Validates the administrator's creation action
 */
export const createAdministratorValidator = vine.compile(
  vine.object({
    name: common.name,
    username: common.username,
    password: common.password,
    roleId: common.roleId,
  })
)

まず、テストファイルをコマンドで作ります。
--suiteでユニットテストを作るか機能テストを作るか指定します。

テストの作成
node ace make:test validators/AdministratorValidator.ts --suite=unit
# tests/unit/validators/administrator_validator.spec.ts

# node ace make:test controllers/AdministratorController.ts --suite=functional
# tests/functional/validators/administrator_validator.spec.ts

作成したユニットテストのファイルを以下のように修正し、正常系と異常系の1パターンずつ検証するテストコードを実装します。
※実際は、網羅的にやる必要があります

administrator_validator.spec.ts
import { Assert } from '@japa/assert';
import { errors, VineValidator } from '@vinejs/vine';
import { SchemaTypes } from '@vinejs/vine/types';

/**
 *
 * @param {Assert} assert
 * @param {VineValidator<SchemaTypes, object>} validator
 * @param {object} requestData
 * @param {string} errorMessage
 * @returns {unknown}
 */
export async function assertValidationError(
  assert: Assert,
  validator: VineValidator<SchemaTypes, object>,
  requestData: object,
  errorMessage: string = 'バリデーションエラーにならずに、正常終了しました'
) {
  try {
    await validator.validate(requestData);
    assert.fail(errorMessage); // バリデーションエラーにならない場合は、テスト失敗
  } catch (error) {
    assert.isTrue(error instanceof errors.E_VALIDATION_ERROR);

    // テストしたパラメータが全てバリデーションエラーとなることを確認
    const errorFields = error.messages.map((err: any) => err.field);
    assert.includeMembers(errorFields, Object.keys(requestData));

    return error;
  }
};

実行してみる

では、テストコードが書けたので実行してみましょう。

node ace test

# 機能テストの実行
# node ace test functional

# ユニットテストの実行
# node ace test unit

実行すると、全てのテスト(2件)が成功していることがわかります。

[ info ] booting application to run tests...
test start

unit / 管理者登録バリデーション (tests/unit/app/validators/administrator_validator.spec.ts)
  ✔ 【正常系】文字列が下限の場合 (5.64ms)
  ✔ 【バリデーションエラー】必須項目が空文字の場合 (4.43ms)
test end

 PASSED 

Tests  2 passed (2)
 Time  160ms

ちなみに、失敗すると以下のようになります。
どこのチェックで失敗しているかも表示してくれますね:smile:

[ info ] booting application to run tests...
test start

unit / 管理者登録バリデーション (tests/unit/app/validators/administrator_validator.spec.ts)
  ✔ 【正常系】文字列が下限の場合 (4.51ms)
  ✖ 【バリデーションエラー】必須項目が空文字の場合 (8.33ms)
test end
────────────────────────────────────────────────────────────────────────────────────────────────── ERRORS ─────────────────────────────────────────────────────────────────────────────────────────────────────

❯ 管理者登録バリデーション / 【バリデーションエラー】必須項目が空文字の場合

- Expected  - 2
+ Received  + 1

  Array [
-   "username",
-   "password",
    "name",
+   "password",
    "roleId",
  ]

ℹ AssertionError: expected [ 'name', 'password', 'roleId' ] to be a superset of [ Array(4) ]

 ⁃ at Assert.includeMembers (/workspace/node_modules/@japa/assert/build/index.js:1168:19)
 ⁃ at Object.executor (tests/unit/app/validators/administrator_validator.spec.ts:48:14)

   43 ┃      } catch (error) {
   44 ┃        assert.isTrue(error instanceof errors.E_VALIDATION_ERROR);
   45 ┃  
   46 ┃        // テストしたパラメータが全てバリデーションエラーとなることを確認
   47 ┃        const errorFields = error.messages.map((err: any) => err.field);
 ❯ 48 ┃        assert.includeMembers(errorFields, Object.keys(requestData));
   49 ┃  
   50 ┃        return error;
   51 ┃      }
   52 ┃      });
   53 ┃  });
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[1/1]─

 FAILED 

Tests  1 passed, 1 failed (2)
 Time  135ms

おわりに

今回は、AdonisJSでユニットテストを書いてみました。
次は、モックを使ったユニットテストを書いてみようと思います!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?