PHPUnit実行環境をDockerでサクッと構築!
はじめに
PHP単体でテストコードの練習がしたいな〜と思い、サクッとDockerでPHPUnitの実行環境を作りました。
Dockerについて勉強中のため、手順などをまとめてみます。
※何かあればご指摘ください・・・!
ソースはこちら
ディレクトリ構成
テスト対象とテストコードはsrc配下に配置します。
PHPUnitをただ試してみたい方は、上記のgithubからソースを取得してください。
├─ src/
│ ├─ tests/FunctionTest.php // テストコード
│ └─ function.php // テスト対象
├─ Dockerfile
└─docker-compose.yml
環境
PHP 8.0
PHPUnit 9.5
Docker Desktop 4.5.0
Docker 20.10.12
Docker Compose 1.29.2
DockerでPHPUnit環境を構築
DockerHubでイメージを選ぶ
基本的には以下の2パターンから選択することになると思います。
- PHP公式イメージにPHPUnitを入れる(composerなどを使って)
- PHPUnitイメージを探して構築する ex. phpunit/phpunit
今回は、PHPの実行環境にComposerでPHPUnitを入れるパターン1 を試してみたいと思います。
PHPの公式イメージのリファレンスを確認する
リファレンスに色々と記載されているので、目を通しておきます。
イメージ選択
PHPの公式イメージの中でさらに種類があるので確認します。
Image Variantsの章を確認すると、以下の種類を確認できます。
Webサーバーが梱包されているイメージもあります。
今回はテスト実行だけなのでphp:<version>-cli
を使います。
- php:<version>-cli
- php:<version>-apache(PHPとApache)
- php:<version>-fpm(PHPとPHP-FPM)
- php:<version>-alpine(PHPとAlpine Linux)
バージョン選択
PHPの公式イメージのTagsから目的のイメージを探します。
今回はphp:8.0-cli
を使うので検索して、あるかどうか確認します。
見つかったらベースイメージとして、Dockerfileを書きましょう。
Dockerfileの作成
Dockerfileの作成にはいくつかのアプローチがあると思います。
例えば、以下のような感じ。
①composerをイメージに含めて、コンテナ内でphpunitを入れる。phpunitもコンテナ内、もしくは外から実行する。
②docker-entrypoint.sh
[1]を作成し、phpunitのインストールやphpunitの実行も実施できるようにする。
②の方がスマートな感じもしますが、今回は①のパターンで、コンテナ内でphpunitのインストールとphpunitの実行したいと思います。
- FROMにベースイメージを指定します。
FROM php:8.0-cli
- PHPUnitのインストールに必要な
zip
とunzip
をインストールします。
RUN apt-get update && apt-get install -y \
zip \
unzip
- Composerをインストールします。
Composerの公式イメージを確認すると、トラブルシューティングの箇所に以下の記述があります。
Docker17.05以上の場合はマルチステージビルドというものが導入されており、こちらの記載のコマンドでComposerをイメージに含めることができます。
めっちゃ便利、、、
※マルチステージビルドについては他の記事をご参照ください。
私たちのイメージは、ホストにPHPランタイムをインストールしなくても、Composerをすばやく実行することを目的としています。コンテナ内のPHPバージョンに依存しないでください。Composerをベースイメージまたは本番イメージとして使用することを推奨したくないため、サポートされているPHPバージョンごとにComposerイメージを提供していません。
提案:
(最適)独自のビルドイメージを作成し、その中にComposerをインストールします。
注: Docker 17.05はマルチステージビルドを導入し、これを大幅に簡素化しました。
COPY --from=composer /usr/bin/composer /usr/bin/composer
COPY /usr/bin/composer /usr/bin/composer
- 最後に作業ディレクトリを設定します。今回は/appとしておきます。
WORKDIR /app
以上でDockerfileは完成です。
最終系はこんな感じです。
FROM php:8.0-cli
RUN apt-get update && apt-get install -y \
zip \
unzip
COPY /usr/bin/composer /usr/bin/composer
WORKDIR /app
docker-compose.ymlの作成
- versionの指定
docker-composeで使用するバージョンの定義のようです。
※ただし、最新のバージョンであるDocker Compose V2では不要のようです。
詳しくはこちらの記事が参考になりますので、紹介させていただきます。
version: '3.9'
- serviceの指定
コンテナの定義をします。
テストソースをマウントして、コンテナでテスト実行できるようにします。
コンテナに入れるようにttyを設定します。
services: # 各コンテナを定義
php: # サービス名
build: ./ # 構築時のオプションを指定、今回はDockerfileの場所
container_name: phpunit # 任意のコンテナ名を設定
tty: true # コンテナを起動し続ける
volumes:
- type: bind # バインドマウントをする(ホストとコンテナを同期)
source: ./ # マウントするソースの場所(ホスト)
target: /app # マウント先の場所
PHPUnitのインストールと実行、削除
Dockerfileのある作業ディレクトリ上にターミナルで移動し、コマンドを実行します。
コンテナの構築、起動
バックグラウンドで実行します。
コンテナが起動中であることを確認してください。
$ docker compose up -d
コンテナに入る
コンテナに入ってComposerを確認します。
$ docker container exec -it phpunit bash
// コンテナ内
~:/app# composer -V
Composer version 2.3.5 ~
ComposerでPHPUnitをインストール
~:/app# composer require --dev phpunit/phpunit
composer.jsonやvendorファイルがホスト側にも作成されます。
{
"require-dev": {
"phpunit/phpunit": "^9.5"
}
}
PHPUnitを実行
PHPUnitが実行できることを確認します。
私のgithubのソースを使っている場合は、1件失敗するようになっています。
~:/app# vendor/bin/phpunit src/tests --testdox
PHPUnit 9.5.20 #StandWithUkraine
Function
✔ Morning
✘ Evening
│
│ Failed asserting that two strings are identical.
│ --- Expected
│ +++ Actual
│ @@ @@
│ -'hello!'
│ +'good evening!'
│
│ /app/src/tests/FunctionTest.php:17
│
✔ Hello
Time: 00:00.311, Memory: 6.00 MB
Summary of non-successful tests:
Function
✘ Evening
│
│ Failed asserting that two strings are identical.
│ --- Expected
│ +++ Actual
│ @@ @@
│ -'hello!'
│ +'good evening!'
│
│ /app/src/tests/FunctionTest.php:17
│
FAILURES!
Tests: 3, Assertions: 3, Failures: 1.
コンテナの停止・削除
PHPUnitを実行するだけのコンテナなので、
利用が終われば削除して、また使いたい場合は実行します。
~:/app# exit
// コンテナの停止・削除
$ docker compose down
終わりに
Dockerを実務で使うことがほとんどないので、
これだけでもかなり大変でした、、、
基本的なことは理解したので、個人でバリバリ使っていきたいと思います!
-
ヘルパー・スクリプトと呼ばれるもので、コンテナの開始時にENTRYPOINTでシェルを実行できます。初回起動の時だけ何かしらのコマンドを実行したい場合などに利用するようです。 ↩︎
Discussion