1. Home
  2. PHP
  3. Laravel
  4. Laravel&CircleCIで継続的インテグレーション。ユニットテスト、静的コード解析、E2Eテストなど。

Laravel&CircleCIで継続的インテグレーション。ユニットテスト、静的コード解析、E2Eテストなど。

  • 公開日
  • カテゴリ:Laravel
  • タグ:PHP,Laravel,PHPUnit,CircleCI,Github,E2ETesting
Laravel&CircleCIで継続的インテグレーション。ユニットテスト、静的コード解析、E2Eテストなど。

Laravelで構築したwebアプリケーションをGithubにてソース管理を行う事も多いですが、CI(continuous integration=継続的インテグレーション)と呼ばれる、ビルドやテストを継続的に行っていきたいところです。

今回はCircleCIとGithubを連携させてLaravelアプリケーションをビルド&テストするまでを見ていきます。

Contents

  1. 開発環境
  2. GithubとCircleCIの連携
    1. GithubアカウントとCircleCIの連携
    2. 任意のリポジトリのCIを開始する
  3. 設定ファイルの作成
    1. 環境構築の定義
  4. DBコネクションの設定
  5. 動作確認
  6. テストの定義
    1. ユニットテスト
    2. コーディング規約チェック
    3. 静的コード解析
    4. E2Eテスト(Dusk)
  7. バージョンによる設定ファイル記法の違い
    1. ver 2.0
    2. var 2.1

開発環境

今回の開発環境については以下の通りです。

  • PHP 7.3
  • MySQL 8.0
  • Laravel 5.8
  • Circle CI 2.0 - 2.1

laravelアプリケーションのルートディレクトリを laravel/ としています。

GithubとCircleCIの連携

GithubからCircleCIを動作させるには、2つのアカウントを連携させてやる必要があります。

GithubアカウントとCircleCIの連携

CircleCIへアクセスし、Githubアカウントでサインインします。

Github上でCircleCIとの連携承認画面になるので、承認するとアカウントの連携が行われ、CircleCIの管理画面へ遷移します。

任意のリポジトリのCIを開始する

CircleCIの管理画面から「Add Projects」に進むと自身のリポジトリの一覧が表示されるので、そこからCIを回したいリポジトリを選んで(Set Up Project)アクティブにする事で、リモートリポジトリに変更が起こるとCircleCIが動作するようになります。(初めての場合は、サインイン後にリポジトリの一覧が既に表示されたような気もするので、その場合はそこから選択してもOK)

ここまでで、Githubのリモートリポジトリへソースをプッシュした際にCircleCIが動作するようになります。

設定ファイルの作成

CIを回すために、設定ファイルである config.yml を作成します。

今回はアプリケーションソースとCIのファイルを分けて管理するので、以下のようなディレクトリ構成にします。

project_root
├── .circleci
|      └── config.yml
|
└── laravel(laravelのソース群)

環境構築の定義

まずは、Laravelアプリケーションを動作させる為の環境構築部分を定義します。

laravel/.circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/php:7.3-stretch-node-browsers
      - image: circleci/mysql:8.0.17
        command: mysqld --default-authentication-plugin=mysql_native_password
    environment:
      - APP_DEBUG: true
      - APP_ENV: testing
      - APP_KEY: base64:YlIJx6uH3OUb3hxN+PAiJKlC+EGZ2KYi8VHxsfdJpLk=
      - DB_CONNECTION: circleci

    working_directory: ~/repo

    steps:
      - checkout

      - run:
          name: install dockerize
          command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
          environment:
            DOCKERIZE_VERSION: v0.6.1

      - run:
          name: Install PHP Extensions
          command: sudo docker-php-ext-install pdo_mysql

      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "laravel/composer.json" }}
            - v1-dependencies-

      - run:
          name: composer install
          working_directory: laravel
          command: composer install -n --prefer-dist

      - save_cache:
          paths:
            - ./vendor
          key: v1-dependencies-{{ checksum "laravel/composer.json" }}

      - run:
          name: Wait for db
          command: dockerize -wait tcp\://localhost:3306 -timeout 1m

      - run:
          name: Migration & Seeding
          working_directory: laravel
          command: php artisan migrate --seed

以下、詳細です。

docker:
  - image: circleci/php:7.3-stretch-node-browsers
  - image: circleci/mysql:8.0.17
    command: mysqld --default-authentication-plugin=mysql_native_password

PHP7.3とMySQL8.0のイメージを導入しています。 MySQLはver8.0の為、認証方式を変更しています。

environment:
  - APP_DEBUG: true
  - APP_ENV: testing
  - APP_KEY: base64:YlIJx6uH3OUb3hxN+PAiJKlC+EGZ2KYi8VHxsfdJpLk=
  - DB_CONNECTION: circleci

環境変数を定義しています。主にテストを走らせる為に必要な設定を行っています。

以下、runコマンドベースです。

install dockerize MySQLコンテナが立ち上がった事を確認してからマイグレーションやシーディングを実行したいので、そのためのdockerizeのインストールを行っています。(導入は任意) Install PHP Extensions PHP拡張をインストールしています。 composer install Laravelの依存パッケージをインストールしています。 Wait for MySQL MySQLコンテナが立ち上がるまでここでWaitします。 Migration & Seeding マイグレーションとシーディングを行っています。 restore_cache/save_cache はジョブを高速化するためのキャッシュ設定です。詳しくは公式ドキュメントを参照してください。

依存関係のキャッシュ
https://circleci.com/docs/ja/2.0/caching/

DBコネクションの設定

Circle CIでDBを使用するので、専用のコネクション設定をLaravel側に定義しておきます。

laravel/config/database.php
'connections' => [
'circleci' => [
'driver' => 'mysql',
        'host' => '127.0.0.1',
        'port' => '3306',
        'database' => 'circle_test',
        'username' => 'root',
        'password' => '',
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
    ],

動作確認

ここまでで一旦コミットしてリモートリポジトリにプッシュしてみます。Circle CIが動作するので、管理画面「job」から経過や結果を確認する事ができます。

ステータスが「SUCCESS」になったら成功です。ここまでで、環境の構築が完了しました。

テストの定義

環境構築が出来たので、テストを動作させるように定義していきます。一通りの設定を列挙していますが、それぞれ導入済みの前提で、採用は任意でどうぞ。

ユニットテスト

ユニットテストを走らせる為に、PHPUnitが動作するように定義します。

laravel/.circleci/config.yml
- run:
    name: Unittest
    working_directory: laravel
    command: ./vendor/bin/phpunit

これ以降の記述もそうですが、今回はアプリケーションソースとcircleciの設定ファイルを分けているので、プロジェクトルートから見たアプリケーションルートを working_directory で指定しています。

コーディング規約チェック

PHP_snifferを用いたコーディング規約チェックを走らせます。

laravel/.circleci/config.yml
- run:
    name: Coding rules check
    working_directory: laravel
    command: ./vendor/bin/phpcs --standard=phpcs.xml ./

静的コード解析

Larastanを用いた静的コード解析を走らせます。

laravel/.circleci/config.yml
- run:
    name: test - Static code analysis
    working_directory: laravel
    command: php artisan code:analyse --paths='app,tests' --level=max

E2Eテスト(Dusk)

Laravel Duskでブラウザテストを走らせます。

laravel/.circleci/config.yml
- run:
    name: Install Chrome Driver
    working_directory: laravel
    command: php artisan dusk:chrome-driver 76

- run:
    name: Start Chrome Driver
    working_directory: laravel
    command: ./vendor/laravel/dusk/bin/chromedriver-linux
    background: true

- run:
    name: Start Laravel Server
    working_directory: laravel
    command: php artisan serve
    background: true

- run:
    name: Run Dusk
    working_directory: laravel
    command: php artisan dusk
    environment:
      APP_URL: http\://localhost:8000

Install Chrome Driver 任意のバージョンのChromeDriverをインストールしています。ここではver.76をしていしていますが、環境に応じて適切なバージョンを指定してください。 Start Chrome Driver ChromeDriverを起動しています。 Start Laravel Server PHP組み込みWebサーバを起動しています。 test - Dusk Duskでブラウザテストを実行しています。 ## 動作確認

テストの定義を行ったら再度コミットしてリモートリポジトリへプッシュします。CircleCIが動作しテストが行われている事が確認できると思います。

こちらも、ステータスが「SUCCESS」になったら成功です。これで、CircleCIを連携させた自動テストの実行環境が構築できました。

バージョンによる設定ファイル記法の違い

ここまででconfig.ymlの記述については断片的に表示していましたが、バージョンによって若干の違いがある(バージョンアップによる新機能を使わなければ同じ記法では書けます)ので、ここでバージョン別のconfig.ymlを記します。

ver 2.0

これまではこのバージョンで紹介してきました。全体像としては以下になります。

laravel/.circleci/config.yml
version: 2.0
jobs:
  build:
    docker:
      - image: circleci/php:7.3-stretch-node-browsers
      - image: circleci/mysql:8.0.17
        command: mysqld --default-authentication-plugin=mysql_native_password
    environment:
      - APP_DEBUG: true
      - APP_ENV: testing
      - APP_KEY: base64:YlIJx6uH3OUb3hxN+PAiJKlC+EGZ2KYi8VHxsfdJpLk=
      - DB_CONNECTION: circleci

    working_directory: ~/repo

    steps:
      - checkout

      - run:
          name: install dockerize
          command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
          environment:
            DOCKERIZE_VERSION: v0.6.1

      - run:
          name: Install PHP Extensions
          command: sudo docker-php-ext-install pdo_mysql

      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "laravel/composer.json" }}
            - v1-dependencies-

      - run:
          name: composer install
          working_directory: laravel
          command: composer install -n --prefer-dist

      - save_cache:
          paths:
            - ./vendor
          key: v1-dependencies-{{ checksum "laravel/composer.json" }}

      - run:
          name: Wait for db
          command: dockerize -wait tcp\://localhost:3306 -timeout 1m

      - run:
          name: Migration & Seeding
          working_directory: laravel
          command: php artisan migrate --seed

      - run:
          name: Coding rules check
          working_directory: laravel
          command: ./vendor/bin/phpcs --standard=phpcs.xml ./

      - run:
          name: Static code analysis
          working_directory: laravel
          command: php artisan code:analyse --paths='app,tests' --level=max

      - run:
          name: Unittest
          working_directory: laravel
          command: ./vendor/bin/phpunit

      - run:
          name: Install Chrome Driver
          working_directory: laravel
          command: php artisan dusk:chrome-driver 76

      - run:
          name: Start Chrome Driver
          working_directory: laravel
          command: ./vendor/laravel/dusk/bin/chromedriver-linux
          background: true

      - run:
          name: Start Laravel Server
          working_directory: laravel
          command: php artisan serve
          background: true

      - run:
          name: Run Dusk
          working_directory: laravel
          command: php artisan dusk
          environment:
            APP_URL: http\://localhost:8000

var 2.1

本記事執筆時点での最新バージョンです。

laravel/.circleci/config.yml
version: 2.1
executors:
  default:
    working_directory: ~/repo
    docker:
      - image: circleci/php:7.3-stretch-node-browsers
      - image: circleci/mysql:8.0.17
        command: mysqld --default-authentication-plugin=mysql_native_password
    environment:
      - APP_DEBUG: true
      - APP_ENV: testing
      - APP_KEY: base64:YlIJx6uH3OUb3hxN+PAiJKlC+EGZ2KYi8VHxsfdJpLk=
      - DB_CONNECTION: circleci
commands:
  install-dockerize:
    steps:
      - run:
          name: Install dockerize
          command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
          environment:
            DOCKERIZE_VERSION: v0.6.1
  install-php-extensions:
    steps:
      - run:
          name: Install PHP Extensions
          command: sudo docker-php-ext-install pdo_mysql
  restore-cache-composer:
    steps:
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "laravel/composer.json" }}
            - v1-dependencies-
  composer-install:
    steps:
      - run:
          name: composer install
          working_directory: laravel
          command: composer install -n --prefer-dist
  save-cache-composer:
    steps:
      - save_cache:
          paths:
            - ./vendor
          key: v1-dependencies-{{ checksum "laravel/composer.json" }}
  wait-for-mysql:
    steps:
      - run:
          name: Wait for MySQL
          command: dockerize -wait tcp\://localhost:3306 -timeout 1m
  migration-seeding:
    steps:
      - run:
          name: Migration & Seeding
          working_directory: laravel
          command: php artisan migrate --seed
  test-static-code-analysis:
    steps:
      - run:
          name: Coding rules check
          working_directory: laravel
          command: ./vendor/bin/phpcs --standard=phpcs.xml ./

      - run:
          name: Static code analysis
          working_directory: laravel
          command: php artisan code:analyse --paths='app,tests' --level=max
  test-unittest:
    steps:
      - run:
          name: Unittest
          working_directory: laravel
          command: ./vendor/bin/phpunit
  test-e2etest:
    steps:
      - run:
          name: Install Chrome Driver
          working_directory: laravel
          command: php artisan dusk:chrome-driver 76
      - run:
          name: Start Chrome Driver
          working_directory: laravel
          command: ./vendor/laravel/dusk/bin/chromedriver-linux
          background: true
      - run:
          name: Start Laravel Server
          working_directory: laravel
          command: php artisan serve
          background: true
      - run:
          name: Run Dusk
          working_directory: laravel
          command: php artisan dusk
          environment:
            APP_URL: http\://localhost:8000
jobs:
  build:
    executor:
      name: default
    steps:
      - checkout
      - install-dockerize
      - install-php-extensions
      - restore-cache-composer
      - composer-install
      - save-cache-composer
      - wait-for-mysql
      - migration-seeding
      - test-static-code-analysis
      - test-unittest
      - test-e2etest

executors 実行環境を定義する事ができ定義を再利用する事が出来ます。 commands ステップシーケンスを予め定義出来るようになっています。これもexecutors同様、コマンドの再利用が出来て便利です。 見て分かる通り、jobsがとてもシンプルになっています。ワークフローを定義する際にも、2.1ではよりすっきり書くことが出来ます。

laravel/.circleci/config.yml
version: 2.1
executors:
  default:
    working_directory: ~/repo
    docker:
      - image: circleci/php:7.3-stretch-node-browsers
    environment:
      - APP_ENV: testing
  testing-image:
    working_directory: ~/repo
    docker:
      - image: circleci/php:7.3-stretch-node-browsers
      - image: circleci/mysql:8.0.17
        command: mysqld --default-authentication-plugin=mysql_native_password
    environment:
      - APP_DEBUG: true
      - APP_ENV: testing
      - APP_KEY: base64:YlIJx6uH3OUb3hxN+PAiJKlC+EGZ2KYi8VHxsfdJpLk=
      - DB_CONNECTION: circleci
commands:
  install-dockerize:
    steps:
      - run:
          name: Install dockerize
          command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
          environment:
            DOCKERIZE_VERSION: v0.6.1
  install-php-extensions:
    steps:
      - run:
          name: Install PHP Extensions
          command: sudo docker-php-ext-install pdo_mysql
  restore-cache-composer:
    steps:
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "laravel/composer.json" }}
            - v1-dependencies-
  composer-install:
    steps:
      - run:
          name: composer install
          working_directory: laravel
          command: composer install -n --prefer-dist
  save-cache-composer:
    steps:
      - save_cache:
          paths:
            - ./vendor
          key: v1-dependencies-{{ checksum "laravel/composer.json" }}
  wait-for-mysql:
    steps:
      - run:
          name: Wait for MySQL
          command: dockerize -wait tcp\://localhost:3306 -timeout 1m
  migration-seeding:
    steps:
      - run:
          name: Migration & Seeding
          working_directory: laravel
          command: php artisan migrate --seed
  test-static-code-analysis:
    steps:
      - run:
          name: Coding rules check
          working_directory: laravel
          command: ./vendor/bin/phpcs --standard=phpcs.xml ./

      - run:
          name: Static code analysis
          working_directory: laravel
          command: php artisan code:analyse --paths='app,tests' --level=max
  test-unittest:
    steps:
      - run:
          name: Unittest
          working_directory: laravel
          command: ./vendor/bin/phpunit
  test-e2etest:
    steps:
      - run:
          name: Install Chrome Driver
          working_directory: laravel
          command: php artisan dusk:chrome-driver 76
      - run:
          name: Start Chrome Driver
          working_directory: laravel
          command: ./vendor/laravel/dusk/bin/chromedriver-linux
          background: true
      - run:
          name: Start Laravel Server
          working_directory: laravel
          command: php artisan serve
          background: true
      - run:
          name: Run Dusk
          working_directory: laravel
          command: php artisan dusk
          environment:
            APP_URL: http\://localhost:8000
jobs:
  build:
    executor:
      name: default
    steps:
      - checkout
      - install-php-extensions
      - restore-cache-composer
      - composer-install
      - save-cache-composer
      - run:
          name: npm install
          working_directory: laravel
          command: npm install
  test:
    executor:
      name: testing-image
    steps:
      - checkout
      - install-dockerize
      - install-php-extensions
      - restore-cache-composer
      - composer-install
      - save-cache-composer
      - wait-for-mysql
      - migration-seeding
      - test-static-code-analysis
      - test-unittest
      - test-e2etest
workflows:
  build-and-test:
    jobs:
      - build
      - test:
          requires:
            - build

まとめ

Laravelアプリケーションのテストを中心に見ていきました。 config.ymlはこれ以外にも記法があるので、最適な記法を用いてシンプル状態で管理していきたいですね。

サンプルコード

Author

rito

  • Backend Engineer
  • Tokyo, Japan
  • PHP 5 技術者認定上級試験 認定者
  • 統計検定 3 級