コンテナーでの Node.js テストの実行

前提条件

本ガイドの Node.js アプリケーションのコンテナー化 から始まる前節までを完了していること。

概要

テストというものは、現代のソフトウェア開発においては重要な工程です。 開発チームによって、テストが意味するところはさまざまです。 ユニットテストがあり、インテグレーションテストがあり、エンドツーエンドテストがあります。 本ガイドでは Docker による開発およびビルド時におけるユニットテストの実行方法について見ていくことにします。

ローカルでの開発時におけるテスト実行

サンプルアプリケーションには、テストを実行するための Jest パッケージが既に含まれていて、spec ディレクトリにテスト関連のファイルがあります。 ローカルにおいて開発を行っているときには Compose を使ってテストを実行することができます。

コンテナー内部には package.json ファイルがあります。 その中のテストスクリプトを実行するために以下のコマンドを実行します。

$ docker compose run server npm run test

上のコマンドの詳細については docker compose run を参照してください。

上のコマンドの出力は以下のようになるはずです。

> docker-nodejs@1.0.0 test
> jest

 PASS  spec/routes/deleteItem.spec.js
 PASS  spec/routes/getItems.spec.js
 PASS  spec/routes/addItem.spec.js
 PASS  spec/routes/updateItem.spec.js
 PASS  spec/persistence/sqlite.spec.js
  ● Console

    console.log
      Using sqlite database at /tmp/todo.db

      at Database.log (src/persistence/sqlite.js:18:25)

    console.log
      Using sqlite database at /tmp/todo.db

      at Database.log (src/persistence/sqlite.js:18:25)

    console.log
      Using sqlite database at /tmp/todo.db

      at Database.log (src/persistence/sqlite.js:18:25)

    console.log
      Using sqlite database at /tmp/todo.db

      at Database.log (src/persistence/sqlite.js:18:25)

    console.log
      Using sqlite database at /tmp/todo.db

      at Database.log (src/persistence/sqlite.js:18:25)


Test Suites: 5 passed, 5 total
Tests:       9 passed, 9 total
Snapshots:   0 total
Time:        2.008 s
Ran all test suites.

ビルド時におけるテスト実行

ビルド時にテストを実行するには、Dockerfile を修正してテストステージを新たに付け加える必要があります。

以下がその修正を行った Dockerfile です。

# syntax=docker/dockerfile:1

ARG NODE_VERSION=18.0.0

FROM node:${NODE_VERSION}-alpine as base
WORKDIR /usr/src/app
EXPOSE 3000

FROM base as dev
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=package-lock.json,target=package-lock.json \
    --mount=type=cache,target=/root/.npm \
    npm ci --include=dev
USER node
COPY . .
CMD npm run dev

FROM base as prod
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=package-lock.json,target=package-lock.json \
    --mount=type=cache,target=/root/.npm \
    npm ci --omit=dev
USER node
COPY . .
CMD node src/index.js

FROM base as test
ENV NODE_ENV test
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=package-lock.json,target=package-lock.json \
    --mount=type=cache,target=/root/.npm \
    npm ci --include=dev
USER node
COPY . .
RUN npm run test

テストステージにおいては CMD の代わりに RUN を使ってテストを実行します。 こうする理由は、CMD 命令がコンテナーの実行時に起動されるものですが、RUN 明理恵はイメージのビルド時に実行されるものであるからです。 しかもテストに失敗した場合はビルドも失敗することになります。

以下のようなコマンドを実行することで、テストステージをターゲットとした新たなイメージをビルドします。 テスト結果をそこから確認します。 --progress=plain をつけるのは、ビルド出力を確認するものです。 また --no-cache はテストが必ず実行されるようにするものであり、--target test はテストステージをターゲットとするものです。

$ docker build -t node-docker-image-test --progress=plain --no-cache --target test .

上のコマンドの出力は以下のようになるはずです。

...

#11 [test 3/3] RUN npm run test
#11 1.058
#11 1.058 > docker-nodejs@1.0.0 test
#11 1.058 > jest
#11 1.058
#11 3.765 PASS spec/routes/getItems.spec.js
#11 3.767 PASS spec/routes/deleteItem.spec.js
#11 3.783 PASS spec/routes/updateItem.spec.js
#11 3.806 PASS spec/routes/addItem.spec.js
#11 4.179 PASS spec/persistence/sqlite.spec.js
#11 4.207
#11 4.208 Test Suites: 5 passed, 5 total
#11 4.208 Tests:       9 passed, 9 total
#11 4.208 Snapshots:   0 total
#11 4.208 Time:        2.168 s
#11 4.208 Ran all test suites.
#11 4.265 npm notice
#11 4.265 npm notice New major version of npm available! 8.6.0 -> 9.8.1
#11 4.265 npm notice Changelog: <https://github.com/npm/cli/releases/tag/v9.8.1>
#11 4.265 npm notice Run `npm install -g npm@9.8.1` to update!
#11 4.266 npm notice
#11 DONE 4.3s

...

まとめ

本節では、ローカル環境での開発時に Compose を使ってテスト実行する方法について、またイメージビルド時にテスト実行する方法について学びました。

関連情報

次のステップ

次は GitHub アクションを使った CI/CD パイプラインの設定方法について学びます。