前提

  • PHP 7.2の場合を想定する
  • PHP 7.2系はPHPUnit 9系に対応していない(PHPUnit 9はPHP 7.3以上が必要)ため、PHPUnit 8系を使用する
  • PHPUnitおよびYoast / PHPUnit-PolyfillsをComposerでインストールする
  • /var/www/htmlにWordPressをインストールしたと仮定して進める
  • WP-CLIを使ってテーマの単体テストの雛形を作成する

docker-compose.yml

WordPressのテスト環境を以下のように設定する。

  test_db:
    image: mysql:5.7
    platform: linux/amd64
    container_name: test_db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: wordpress_test
      MYSQL_DATABASE: wordpress_test
      MYSQL_USER: wordpress_test
      MYSQL_PASSWORD: wordpress_test

Composerをインストール

# Install Composer for PHPUnit
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
 && php -r "if (hash_file('sha384', 'composer-setup.php') === file_get_contents('https://composer.github.io/installer.sig')) { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
 && php composer-setup.php \
 && php -r "unlink('composer-setup.php');" \
 && chmod u+x composer.phar \
 && mv composer.phar /usr/local/bin/composer

参考: Download Composer

※ 元のコードはComposerインストーラーの検証ハッシュ値を文字列としてハードコードしていたが、このハッシュ値はComposer側のインストーラー更新にともなって変わるため、ハードコードすると将来的に「Installer corrupt」の誤判定を起こす可能性がある。公式ダウンロードページが案内している、https://composer.github.io/installer.sigから最新のハッシュ値を都度取得して比較する方法に修正した。

PHPUnitおよびYoast / PHPUnit-Polyfillsをインストール

Yoast / PHPUnit-Polyfillsは、WordPressの単体テストで必要になる。

composer.json

{
  "autoload-dev": {
    "psr-4": {
      "MyTheme\\Tests\\": "wp-content/themes/my-theme/tests/"
    }
  },
  "require-dev": {
    "phpunit/phpunit": "^8.0",
    "yoast/phpunit-polyfills": "^2.0"
  }
}

Dockerfile

composer.jsonをコンテナにコピーする。

# Install PHPUnit & PHPUnit Polyfills
COPY ./composer.json /var/www/html/composer.json
RUN cd /var/www/html \
 && env COMPOSER_ALLOW_SUPERUSER=1 composer install \
 && composer dump-autoload

※ 元のコードはcd wpとなっていたが、直前でcomposer.jsonをコピーしている先は/var/www/htmlなので、cd /var/www/htmlに修正した。

phpunit.xml.dist

テーマディレクトリ(例: my-theme)にphpunit.xml.distを作成する。

<?xml version="1.0"?>
<phpunit
	bootstrap="tests/bootstrap.php"
	backupGlobals="false"
	colors="true"
	convertErrorsToExceptions="true"
	convertNoticesToExceptions="true"
	convertWarningsToExceptions="true"
	>
	<php>
	        <const name="WP_TESTS_PHPUNIT_POLYFILLS_PATH" value="/var/www/html/vendor/yoast/phpunit-polyfills"/>
        </php>
	<testsuites>
		<testsuite name="testing">
			<directory prefix="test-" suffix=".php">./tests/</directory>
		</testsuite>
	</testsuites>
</phpunit>

参考

WP-CLIを使用してユニットテストをセットアップ

コンテナ内でwp scaffold theme-testsコマンドを発行する。

container$ cd /var/www/html/wp-content/themes
container$ wp scaffold theme-tests my-theme

my-themeディレクトリにbin/install-wp-tests.shが作成される。

bin/install-wp-tests.shを実行

コンテナ内で実行する。

container$ cd /var/www/html/wp-content/themes/my-theme
container$ bin/install-wp-tests.sh wordpress_test wordpress_test wordpress_test test_db

テスト実行

container$ ../../../vendor/bin/phpunit

サンプル

<?php
/**
 * WP_UnitTestCaseのサンプル
 *
 * @package MyTheme
 */
class Sample_Test extends WP_UnitTestCase {

	/**
	 * 単一ページテスト
	 *
	 * @link http://qiita.com/miya0001/items/8f1a777b455a8bdcbd62
	 */
	public function test_the_title() {
		$post = $this->post_ids = $this->factory->post->create_and_get( array(
			'post_title' => 'Sample Post!',
		) );
		$this->go_to( '/?p=' . $post->ID );
		$this->assertTrue( is_single() );
		$this->expectOutputString( 'Sample Post!' );
		the_title();
	}

	/**
	 * アーカイブテスト
	 */
	public function test_single_cat_title() {
		$cat = $this->factory->category->create_and_get( array( 'name' => 'Sample Category' ) );
		$this->factory->post->create( array( 'post_category' => array( $cat->term_id ) ) );
		$this->go_to( '/?cat=' . $cat->term_id );
		$this->assertTrue( is_archive() );
		$this->assertFalse( is_single() );
		$this->expectOutputString( 'Sample Category' );
		single_cat_title();
	}
}

※ サンプルコードのPHPDocに含まれていた実在の個人名・メールアドレス・パッケージ名は、汎用的なプレースホルダーに置き換えた。