概要
プログラミングすることがめっきり少なくなったのですが、プログラミングはとても好きで、図書館でこちらの本を借りてきました。
フロントエンド開発のためのテスト入門 - Amazon | Kindle
UNITテストの自動化がわかりやすく、とても勉強になりました。
そしてDockerコンテナでテスト環境を配れたりしたら素敵だなと思って、javascriptのUNITテスト環境をDockerコンテナで作ってみました。
UNITテストのツールは jest(https://jestjs.io/ja/) を導入しています。
最終的にできること
Dockerコンテナ内にjavascriptアプリのunitテスト(jest)の環境を作ります。
以下は、そのコンテナ内でのUNITテストの実行がPASSした結果です。
root@edf58454f2f8:/usr/src/app# npm test
> docker_web_app@1.0.0 test
> jest
PASS ./sum.test.js
✓ adds 1 + 2 to equal 3 (1 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.208 s
Ran all test suites.
前提
PCにDockerDesktopがインストールされていること。
node.js version 20をベースにしています。
3種類のnodejsのDockerイメージ
node.jsは大きく分けて以下3種類のDockerイメージがあります。
今回は、以下のとおりデファクトイメージのnode:<version>を使うとよいです。
node:<version>
これがデファクトイメージです。自分のニーズが何かわからない場合は、おそらくこれを使用するとよいでしょう。これは、使い捨てコンテナ (ソース コードをマウントし、コンテナを起動してアプリを起動する) としても、他のイメージを構築するためのベースとしても使用できるように設計されています。node: <version> -alpine
このイメージは、公式イメージで入手できる人気のあるAlpine Linux プロジェクトに基づいています。>Alpine Linux は、ほとんどのディストリビューション ベース イメージ (約 5MB) よりもはるかに小さいため、一般的にイメージがよりスリムになります。alpinenode:<version>-slim
このイメージには、デフォルト タグに含まれる共通パッケージは含まれておらず、実行に必要な最小限のパッケージのみが含まれていますnode。イメージのみがデプロイされ、スペースの制約がある環境で作業している場合を除きnode、このリポジトリのデフォルトのイメージを使用することを強くお勧めします。
(引用元:https://hub.docker.com/_/node)
こちらにもnodeイメージの選定について同じ意見がありました。
近年、slimイメージは150MBまでサイズが小さくなっており、かつさまざまな状況で最もよく動作するようになっています。 Alpineはとても小さなコンテナディストリビューションで、最小のnodeイメージはたった75MBです。しかし、パッケージマネージャをaptからapkに取り替えたり、 特別な状況 に対応したり、 セキュリティスキャンの制限 を回避したりする努力をするくらいなら、ほとんどの場合node:alpineをお勧めしません。
(引用元:https://www.creationline.com/tech-blog/29422)
完成時のディレクトリ構成
適宜どこかにプロジェクトフォルダ(YOUR-PROJECT-FOLDER)を作成して、以降で以下のファイルを作っていきます。
YOUR-PROJECT-FOLDER
├package.json -----npmでパッケージを管理するために使われる構成ファイル
├server.js -----Webアプリ
├Dockerfile -----Dockerfile
├.dockerignore -----dockerイメージに含めないファイル
├sum.js -----サンプルコード
└sum.test.js -----サンプルコード(sum.js)の単体テスト用のコード
各ファイル
package.json
https://nodejs.org/ja/docs/guides/nodejs-docker-webapp にあるpackage.jsonを編集し、"scripts"に"jest"を追加しています。
{
"name": "docker_web_app",
"version": "1.0.0",
"description": "Node.js + jest on Docker",
"author": "First Last <first.last@example.com>",
"main": "server.js",
"scripts": {
"start": "node server.js",
"test": "jest"
},
"dependencies": {
"express": "^4.16.1"
},
"devDependencies": {
"jest": "^29.7.0"
}
}
Dockerfile
Dockerfileもhttps://nodejs.org/ja/docs/guides/nodejs-docker-webapp にあるDockerfileを編集して、
npm install --save-dev jest
追加すると、全体は次のような定義になります。
#FROM node:12
FROM node:20
# アプリケーションディレクトリを作成する
WORKDIR /usr/src/app
# アプリケーションの依存関係をインストールする
# ワイルドカードを使用して、package.json と package-lock.json の両方が確実にコピーされるようにします。
# 可能であれば (npm@5+)
COPY package*.json ./
RUN npm install && \
npm install --save-dev jest
# 本番用にコードを作成している場合
# RUN npm install --only=production
# アプリケーションのソースをバンドルする
COPY . .
EXPOSE 8080
CMD [ "node", "server.js" ]
sample.js
サンプルのコードを用意します。今回は簡単な足し算にしてみました。
function sum(a, b) {
return a + b;
}
module.exports = sum;
sample.test.js
sample.jsのテストコードを作ります。サンプルコードの結果が「1+2=3にるか」を評価したUNITテストです。
const sum = require('./sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
.dockerignore
これはなくてもよいのですが、dockerに無視して欲しいファイルを記載しています。
node_modules
npm-debug.log
dockerイメージのbuild
プロジェクトフォルダ内(以下ではdocker-webapp-jest)に移動して、作成したDockerfileでDockerイメージをビルドします。ビルドコマンドは、
docker build . -t ryu/node-web-app
としています。オプション(-t)は、 名前:タグ の形式で指定しますが、名前のみつけて、ryu/node-web-app としました
docker-webapp-jest % docker build . -t ryu/node-web-app
[+] Building 74.3s (10/10) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 37B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 34B 0.0s
=> [internal] load metadata for docker.io/library/node:12 7.7s
=> [1/5] FROM docker.io/library/node:12@sha256:01627afeb110b3054ba4a1405541ca095c8bfca1cb6f2be9479c767a2711879e 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 688B 0.0s
=> CACHED [2/5] WORKDIR /usr/src/app 0.0s
=> [3/5] COPY package*.json ./ 0.0s
=> [4/5] RUN npm install && npm install --save-dev jest 65.9s
=> [5/5] COPY . . 0.0s
=> exporting to image 0.5s
=> => exporting layers 0.5s
=> => writing image sha256:9b90a3ebd100cb3bea82c80b97caa4f8b5d3238bd7711c87004328bb1a0169fe 0.0s
=> => naming to docker.io/ryu/node-web-app
Dockerの起動
ビルドしたイメージでDockerコンテナを起動します。
外部ポートは49161をコンテナ内の8080にポートフォワードします。
docker-webapp-jest % % docker run -p 49161:8080 -d ryu/node-web-app
# Dockerコンテナの起動を確認
コンテナの起動をdocker psコマンドで確認します。STATUSがUPとなればOKです。
docker-webapp-jest %docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
77f093b9b8ab ryu/node-web-app "docker-entrypoint.s…" 34 seconds ago Up 32 seconds 0.0.0.0:49161->8080/tcp, :::49161->8080/tcp elegant_dirac
外部からコンテナ内のWebアプリにアクセスできることをcurlで確認
docker-webapp-jest % curl -i localhost:49161
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 11
ETag: W/"b-Ck1VqNd45QIvq3AZd8XYQLvEhtA"
Date: Sat, 07 Oct 2023 04:30:39 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Hello World%
Hello Worldが出力され、外部からWebアクセスできました。
Dockerコンテナに入る
docker execコマンドでDockerコンテナ内に入ります。-it オプション指定し、コンテナIDを指定(この例では77f093b9b8ab)します。
コンテナ内ではnpm testコマンドでjestを実行します。
docker-webapp-jest % docker exec -it 77f093b9b8ab /bin/bash
root@77f093b9b8ab:/usr/src/app# npm test
> docker_web_app@1.0.0 test
> jest
PASS ./sum.test.js
✓ adds 1 + 2 to equal 3 (1 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.208 s
Ran all test suites.
無事にUNITテストを実行できました。