はじめに
本記事はCircleCIを利用して、PHPUnitでCIの自動化を実施することを目的とし、以下の図をワンシーケンス通す備忘録とする。
GitHubのリポジトリはこちら
環境
macOS Catalina:10.15.5(19F101)
php 7.4.9
composer 1.10.10
PHPUnit 9.3.7
目次
- 前提条件
- CircleCIを登録する
- GitHubでCI連携用のリポジトリを作る
- composerを取得する
- composerでPHPUnitをインストールする
- PHPUnitで手動実行するテストファイルを作成する
- PHPUnitを手動実行する
- CircleCIとGitHubで作成したリポジトリを連携する
- CircleCIでPHPUnitを動作させるためにGitHubにTestコードを修正してプッシュしてみる
- おまけ・・・config.yml作成時につまづいた点について
前提条件
本記事の手順については、予めGitHubの登録作業が実施済であることを前提とする。また、上記の図にある通り以下技術についての知識が必要。
- git
- docker
- php
- composer
- PHPUnit
- UNIXコマンド
CircleCIを登録する
-
CircleCIにアクセス
- 「Sign up with GitHub」をクリックする
- GitHubで未認証の場合は、CircleCIとの認証を促されるため、GitHubアカウントで認証する。
- 以下のような画面になる。
GitHubでCI連携用のリポジトリを作る
- GitHubにログインする(GitHubの登録は予め実施しておく必要がある。)
- Newをクリックする。
- 「Repository name」に任意のリポジトリ名を入力する。今回は「circleci-phpunit」を設定。
- 「Create repository」をクリックすると以下の画面が表示される。
- ベアリポジトリ(GitHub側)とノンベアリポジトリ(ローカル側)の現在の状態毎の、GitHubとの連携方法を提示してくれる。今回は「...or create a new repository on the command line」(ローカルにノンベアリポジトリを作成してからベアリポジトリにプッシュする方法)を採用することとする。
- 上記のコマンドを枠内の右上のアイコンをクリックしてコピーする。
- git管理するフォルダを作成する。
今回はリポジトリ名(circleci-phpunit)と同じ名前で作成する。 - 「terminal.app」を開き、作成した「circleci-phpunit」階層に移動して、GitHubの画面のアイコンでコピーしたものを貼り付けて実行する。
- GitHubページにコマンドで追加した「README.md」が存在すればリポジトリの操作準備完了。
composerを取得する
composerを取得するには予めphpをmacにインストールしてパスを切っておく必要がある。ちなみにmacには最初からphpが入っているが、macOSのバージョンをあげるとphpの設定がbackupとして変わってしまうことがあるので私の環境ではxamppをダウンロードしてxamppないの「xamppfies/bin」にパスを通して置きphpコマンドをterminalから利用できるようにしている。この状態であれば以下の手順でcomposerのダウンロードが可能となる。
まずはcomposerをダウンロードしたいディレクトリに移動する。
cd プロジェクトのフォルダ
その後以下を参考にcomposerをダウンロードする。
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === 'e5325b19b381bfd88ce90a5ddb7823406b2a38cff6bb704b0acc289a09c8128d4a8ce2bbafcd1fcbdc38666422fe2806') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
composer.pharをダウンロード後、拡張子を除いてダウンロードしたcomposerが動作するか確認する。※pharのままでも動作可能だが、コマンド短縮のため拡張子は省く。
sakamotoyuya:circleci-phpunit sakamotoyuya$ mv composer.phar composer
sakamotoyuya:circleci-phpunit sakamotoyuya$ ./composer -v
______
/ ____/___ ____ ___ ____ ____ ________ _____
/ / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
/_/
Composer version 1.10.10 2020-08-03 11:35:19
Usage:
command [options] [arguments]
Options:
・・・
composerでPHPUnitをインストールする
- ダウンロードしたcomposerと同一階層(以後ルートディレクトリという)に「composer.json」ファイルを以下の内容で作成する。
PHPUnit本家サイトstartupを参考にして実施。
{
"autoload": {
"classmap": [
"src/"
]
},
"require-dev": {
"phpunit/phpunit": "^9"
}
}
オートロード(autoload)方法にはpsr-4
、psr-0
、classmap
、files
とあるが、今回は規定したディレクトリ内を全て読み込むclassmap
を対象にすることとする。
オートロードの詳細は以下を参考。
composerドキュメント - オートロード
オートロードの指定先をsrc/
として、このフォルダは以下のモジュールを自動読み込み対象ファイルとする。
require-dev
はパッケージリンクという。
パッケージリンクの詳細は以下を参考。
composerドキュメント - パッケージリンク
パッケージリンクにはrequire
(本番用)とrequire-dev
(開発用)の二つがある。
これについての使い方の詳細は以下がわかりやすいため参照。
【Laravel】composer require-devの開発、本番での切り分け
$ composer install --no-dev
開発用パッケージは本番環境では不要ですので、--no-devオプションを付けcomposerコマンドを実行する。
そうするとrequire-devオプションに記載されているライブラリ自体はvendorへインストールされません
要するにコンパイルオプションを切り替えることで、パッケージの導入可否を決定する。本番用ではPHPUnitを使わないため、require-dev
に入れて--no-devをコンパイルオプションを付与することで、導入しない動作となる。
- ルートディレクトリにsrcフォルダを作成する。
- 以下のようなフォルダ構造となる。
ルートディレクトリ
|- .git ・・・隠しフォルダ
|- src ・・・フォルダ
|- composer ・・・ファイル
|- composer.json ・・・ファイル
|- README.md ・・・ファイル
- ルートディレクトに移動する。
cd ルートディレクトリ
- 以下のコマンドでPHPUnitをインストールする。
$ ./composer install
composerのコマンドを実行するには、実行ファイルcomposer
とその実行ファイルが読み取る設定ファイルcomposer.json
が必要となる。そのファイルが置いてある箇所に移動して実行する必要がある。
本手順でvendorフォルダが作成される。
vendorフォルダは以下にパッケージがインストールされていくのですが、このフォルダは大きくなったり可変することが多いので、.gitignoreファイルを作ってgit管理の対象外にする。
- 以下の内容で.gitignoreファイルを作る。
vendor
- ディレクトリは以下のようになる。
ルートディレクトリ
|- .git ・・・隠しフォルダ
|- .gitignore ・・・⭐️ファイル
|- src ・・・フォルダ
|- vendor ・・・⭐️composerによりインストールされたフォルダ
| |- bin
| | |- phpunit・・・⭐️phpunitの実行ファイル
| ~
|- composer ・・・ファイル
|- composer.json ・・・ファイル
|- README.md ・・・ファイル
PHPUnitで手動実行するテストファイルを作成する
- srcフォルダに運用するモジュールのHuman.phpを作成する
<?php
class Human{
public function helloString(){
return "こんにちわ";
}
public function goodnightString(){
return "おやすみ";
}
}
- ルートフォルダにtestsフォルダを作成する。フォルダ構成は以下のようになる。
ルートディレクトリ
|- .git ・・・隠しフォルダ
|- src ・・・フォルダ
| |- Human.php ・・・⭐️評価対象モジュール
|
|- tests ・・・⭐️フォルダ
|- vendor ・・・composerによりインストールされたフォルダ
| |- bin
| | |- phpunit・・・phpunitの実行ファイル
| ~
|- composer ・・・ファイル
|- composer.json ・・・ファイル
|- README.md ・・・ファイル
- testsフォルダにHuman.phpをテストするための、テストコードHumanTest.phpを作成する
<?php
use PHPUnit\Framework\TestCase;
final class SakamotoTest extends TestCase{
public function testA(){
$obj = new Human();
$this->assertSame("こんにちわ",$obj->helloString());
}
public function testB(){
$obj = new Human();
// $this->assertSame("おーまいっが!",$obj->goodnightString());
$this->assertSame("おやすみ",$obj->goodnightString());
}
public function testD(){
$obj = new Human();
$this->assertSame("おやすみ",$obj->goodnightString());
}
}
テストコードのファイル名には決まりがあり、「テストしたいモジュールのファイル名+Test.php」
のようにする必要がある。今回Human.php
をテストしたいので、ファイル名はHumanTest.php
となる。また、HumanTest.php
の中身のクラス名はファイル名と異なっても動作可能なようです。試しにSakamotoTest
クラスにしてもテスト実行可能でした。そうする意味もないので、クラス名はファイル名に合わせてHumanTest
にした方が可読性がいいですね。今回は上記の通りお試しのコードとなっているが、実際に作る際はHumanTest
クラスとしましょう。
- このときのフォルダ構成は以下となる
ルートディレクトリ
|- .git ・・・隠しフォルダ
|- src ・・・フォルダ
| |- Human.php ・・・評価対象モジュール
|
|- tests ・・・フォルダ
| |- HumanTest.php・・・⭐️Testファイル
|
|- vendor ・・・composerによりインストールされたフォルダ
| |- bin
| | |- phpunit・・・phpunitの実行ファイル
| ~
|- composer ・・・ファイル
|- composer.json ・・・ファイル
|- README.md ・・・ファイル
PHPUnitを手動実行する
- ソースコードを更新したので、オートロードを更新する
$ ./composer dump-autoload
プロジェクトのファイルを更新した場合はこのコマンドを実行する必要がある。
これを実施しないと変更前の状態での開始となっている。
- PHPUnitを手動実行する
$ ./vender/bin/phpunit tests
テストコードのあるフォルダを指定する。今回はtestsフォルダを指定する。
問題なければ以下のような結果になる。
sakamotoyuya:circleci-phpunit sakamotoyuya$ ./vendor/bin/phpunit tests
PHPUnit 9.3.7 by Sebastian Bergmann and contributors.
Warning: Test case class not matching filename is deprecated
in /Users/sakamotoyuya/Documents/GitHub/circleci-phpunit/tests/HumanTest.php
Class name was 'SakamotoTest', expected 'HumanTest'
... 3 / 3 (100%)
Time: 00:00.016, Memory: 4.00 MB
OK (3 tests, 3 assertions)
... 3 / 3 (100%)
Time: 29 ms, Memory: 4.00 MB
OK (3 tests, 3 assertions)
このように結果がOKであればテストOKということです。
サンプルコードHumanTest.php
は文字列比較しているだけなので、コメントアウト箇所を入れ替えることでNGの場合も確認できる。手動での確認はここまで。
いよいよ次からこの流れをCircleCIを用いて自動化する。
- ここまでできたら、コミットしてGitHubにプッシュする。
git add .
git commit -m "phpunitでテスト環境を作成"
git push
CircleCIとGitHubで作成したリポジトリを連携する
- CircleCIにログイン > Projectsを開く
CircleCI登録時にGitHubと連携しているため、GitHubで作成したリポジトリ一覧が表示される。 -
circleci-phpunit
のSet Up Project
をクリック
-
Use Existing Config
をクリック
config.ymlファイルを追加しましたか?
すでに.circleci / config.ymlを追加している場合は、プロジェクトの構築を開始できる。
そうでない場合は、ビルドを開始する前に、config.ymlファイルをダウンロードして、
リポジトリのルートにある.circleciという名前の新しいフォルダーに追加する。
ルートディレクトリ直下に.circleci/config.yml
の設定ファイルが必要とのことなので、これに従って設定ファイルを作っていく。
- .circleci/config.ymlを以下の内容で作成する。
version: 2.1
jobs:
build:
environment:
TZ: "Asia/Tokyo"
DEBIAN_FRONTEND: noninteractive
docker:
- image: ubuntu:latest # the primary container, where your job's commands are run
environment:
TZ: "Asia/Tokyo"
DEBIAN_FRONTEND: noninteractive
steps:
- checkout # check out the code in the project directory
- run: apt-get update && apt-get install -y tzdata
- run: apt-get install -y wget sudo gnupg
- run: sudo apt-get update
- run: sudo apt-get upgrade -y
- run: sudo apt install -y php
- run: sudo apt-get install -y php-mbstring
- run: sudo apt-get install -y php-xml
- run: sudo apt-get install -y zip
- run: sudo apt-get install -y unzip
- run: echo "Set disable_coredump false" >> /etc/sudo.conf
- run: php ./composer install && ./vendor/bin/phpunit tests
設定ファイルの詳細は後で記載する。
- 現在のフォルダ構成は以下の通りとなる
ルートディレクトリ
|- .git ・・・隠しフォルダ
|- .circleci
| |- config.yml ・・・⭐️circleciの設定ファイル
|
|- src ・・・フォルダ
| |- Human.php ・・・評価対象モジュール
|
|- tests ・・・フォルダ
| |- HumanTest.php・・・Testファイル
|
|- vendor ・・・composerによりインストールされたフォルダ
| |- bin
| | |- phpunit・・・phpunitの実行ファイル
| ~
|- composer ・・・ファイル
|- composer.json ・・・ファイル
|- README.md ・・・ファイル
- 設定ファイルを作成したら再度コミットしてプッシュする。
git add .
git commit -m "CircleCIの設定ファイル(config.yml)を作成"
git push
※GitHubの画面は省略する。
- CircleCIへログイン > Projects > phpunit-circleciのSet Up Project > Use Existing Config > Start Buildingをクリックする。
このようになるのでcircleci-phpunit #2
Actionsの一番左のアイコンをクリックする。
セットアップできているか確認できるのでSUCCESSとなっていれば問題ありませんね。
CircleCIとGitHubリポジトリとの連携は完了です。
これでローカルのソースコードを修正してGitHubにプッシュした際にCircleCIが自動的にデバッグphpunitを実行してくれる環境を作成することができました。
実際にプッシュして試す。
CircleCIでPHPUnitを動作させるためにGitHubにTestコードを修正してプッシュしてみる
- すでに成功する環境が作ってあるので、
README.md
にテストを追加してcommitしてプッシュする。
# circleci-phpunit
テスト
コマンドで以下を実行する。
git add .
git commit -m "README.mdの修正"
git push
-
CircleCI > Projects > phpunit-circleciをクリックするとこのようになっている。
RUNNING状態でconfig.yml
ファイルに従ってビルド実行中がわかる。 -
build
をクリックすると以下の画面になる。
この画面は、config.ymlファイルの設定に従って実行中の実行内容がリアルタイムで閲覧可能な画面になりる。
config.yml
ファイルを修正する際は、config.yml修正後にpush操作をして、この画面をみながら問題有無をチェックして問題あれば修正するという流れとする。
この画像ではすでにSUCCESS表示となっているが、CircleCIの無料版ではビルド時間に制限があるので、ここを確認してビルドが終わらないような問題がある場合は「・・・」からビルドの停止ができるので停止するなどしましょう。ビルドが成功または失敗する場合は、ビルド終了となる。 -
CircleCIでビルドが成功するとGitHub表示も成功表示となる。
緑色のチェック表示が入り、ビルドに失敗すると×表示となる。
おまけ・・・config.yml作成時につまづいた点について
- circleciでcheckoutした後にいる、現在の作業ディレクトリはGitHubからcheckoutしたプロジェクトのルートディレクトリとなる
- phpインストール時にタイムゾーンが聞かれてずっと停止したままとなってしまっていた。
- DockerでUbuntuを立ててそれ上に構築しようとしていたため以下を参考にしていたがわからず。
https://qiita.com/yagince/items/deba267f789604643bab - で、以下の記事を参考にtzdataをインストールすることで解決した。
https://sleepless-se.net/2018/07/31/docker-build-tzdata-ubuntu/ - タイムゾーンの設定の仕方はこれを参考にした。
- runコマンドでUNIXコマンドが叩ける。
- circleciのWEB画面上で環境変数の設定が実はできる。
- CircleCIドキュメント上の上部の検索窓も便利