1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【超入門】PHPのテストコードって何?PHPUnitの使い方を手を動かしながら理解する

1
Posted at

はじめに

「テストコードって聞いたことはあるけど、実際どう書けばいいのかわからない」
「PHPUnitって名前は知ってるけど、なんとなく難しそうで避けてきた」

そんな方に向けて、この記事では PHPのテストコードとは何か から始まり、PHPUnitのインストール〜設定〜実際にテストを書いて実行する ところまで、実際に手を動かしながら理解できるように解説します。

この記事を読み終える頃には、

  • テストコードが何のためにあるのか
  • PHPUnitの環境構築
  • テストコードの書き方
  • 「このテストは大丈夫」と判断する方法(グリーン/レッド、カバレッジ)

がイメージしていただけたら幸いです。


1. テストコードとは何か

1-1. そもそも「テスト」とは

プログラムを書いていると、必ず「このコード、ちゃんと動くんだっけ?」と不安になる瞬間があります。

通常、動作確認は以下のような方法で行われがちです。

  • ブラウザでページを開いて目視確認する
  • var_dump()echo で値を出力して確認する
  • 実際にAPIを叩いてPostmanで確認する

これらは手動テストと呼ばれます。手軽ですが、以下のような問題があります。

  • 毎回同じ手順を人間がやる必要があり、時間がかかる
  • 確認を忘れる、確認漏れが発生する
  • 修正のたびに「ここも壊れてないか」を全部人力で確認するのは非現実的

1-2. テストコードとは

テストコードとは、「このコードは期待通りに動くか」をプログラム自身に確認させるためのコードです。

例えば、「2つの数字を足し算する関数」があったとします。

function add(int $a, int $b): int
{
    return $a + $b;
}

このとき、「add(1, 2) を実行したら 3 が返ってくるはず」という期待値を、コードとして書いておきます。

// テストコードのイメージ
assert(add(1, 2) === 3);

これを実行するだけで、「本当に3が返ってきているか」を一瞬で確認できます。人間がブラウザを開いて確かめる必要はありません。

1-3. テストコードのメリット

メリット 説明
高速に動作確認できる コマンド一発で全機能をチェックできる
修正時の安心材料になる 修正後にテストを流すだけで「壊れていないか」がわかる
仕様書代わりになる テストを見れば「この関数は何をすべきか」が読み取れる
バグの早期発見 本番リリース前に問題に気づける

このテストコードを効率的に書いて実行するための「道具(フレームワーク)」が、PHPの世界では PHPUnit です。


2. テストの種類(ざっくりでOK)

いきなり全部覚える必要はありませんが、言葉だけ知っておくと理解がスムーズです。

  • 単体テスト(Unit Test):関数やクラス単体が正しく動くかを確認するテスト。この記事で扱うのはこれです。
  • 結合テスト(Integration Test):複数のクラスやDBなど、組み合わせた際の動作を確認するテスト。
  • E2Eテスト(End to End Test):ブラウザ操作など、実際のユーザー操作に近い形で確認するテスト。

PHPUnitは主に単体テストのためのツールですが、工夫次第で結合テストにも使えます。まずは単体テストから始めましょう。


3. PHPUnitとは

PHPUnit は、PHPで最も広く使われているテスティングフレームワークです。

  • テストコードを「クラス」と「メソッド」という形で整理して書ける
  • コマンド一発で全テストを実行できる
  • 「成功(グリーン)」「失敗(レッド)」を明確に表示してくれる
  • Composerで簡単に導入できる

多くのPHPフレームワーク(Laravel、Symfonyなど)も標準でPHPUnitを利用しています。


4. 環境構築

4-1. 前提条件

以下がインストールされている必要があります。

  • PHP(7.3以上推奨、できれば8.x系)
  • Composer(PHPのパッケージ管理ツール)

バージョン確認は以下のコマンドで行えます。

php -v
composer -v

もしComposerが入っていない場合は、公式サイトからインストールしてください。

4-2. プロジェクトの作成

作業用フォルダを作ります。

mkdir php-testing-sample
cd php-testing-sample
composer init -n

composer init -n を実行すると composer.json が自動生成されます。

4-3. PHPUnitのインストール

以下のコマンドでPHPUnitを開発用パッケージとしてインストールします。

composer require --dev phpunit/phpunit

インストールが完了すると、vendor/bin/phpunit というコマンドが使えるようになります。動作確認をしてみましょう。

./vendor/bin/phpunit --version

バージョン情報が表示されればインストール成功です。

4-4. ディレクトリ構成

以下のような構成にします。

php-testing-sample/
├── composer.json
├── src/
│   └── Calculator.php      // 本体のコード
├── tests/
│   └── CalculatorTest.php  // テストコード
├── vendor/
└── phpunit.xml             // PHPUnitの設定ファイル

src フォルダにアプリ本体のコードを、tests フォルダにテストコードを置くのが一般的な慣習です。

4-5. オートロードの設定

composer.json を開いて、autoload の設定を追加します(Composerで名前空間からファイルを自動で読み込めるようにする設定です)。

{
    "require-dev": {
        "phpunit/phpunit": "^10.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    }
}

設定を反映させるために、以下のコマンドを実行します。

composer dump-autoload

5. 実際にテストコードを書いてみる

5-1. テスト対象のコードを作る

まずはテストされる側、「電卓クラス」を作ります。

src/Calculator.php

<?php

namespace App;

class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }

    public function subtract(int $a, int $b): int
    {
        return $a - $b;
    }

    public function divide(int $a, int $b): float
    {
        if ($b === 0) {
            throw new \InvalidArgumentException('0で割ることはできません');
        }

        return $a / $b;
    }
}

5-2. テストコードを書く

tests/CalculatorTest.php

<?php

namespace Tests;

use App\Calculator;
use PHPUnit\Framework\TestCase;

class CalculatorTest extends TestCase
{
    private Calculator $calculator;

    // 各テストの実行前に自動で呼ばれる
    protected function setUp(): void
    {
        $this->calculator = new Calculator();
    }

    public function test_add_returns_correct_sum(): void
    {
        $result = $this->calculator->add(1, 2);

        $this->assertSame(3, $result);
    }

    public function test_subtract_returns_correct_difference(): void
    {
        $result = $this->calculator->subtract(5, 3);

        $this->assertSame(2, $result);
    }

    public function test_divide_returns_correct_quotient(): void
    {
        $result = $this->calculator->divide(10, 2);

        $this->assertSame(5.0, $result);
    }

    public function test_divide_by_zero_throws_exception(): void
    {
        $this->expectException(\InvalidArgumentException::class);

        $this->calculator->divide(10, 0);
    }
}

5-3. コードの解説

  • extends TestCase:PHPUnitのテストクラスは必ず TestCase を継承します。
  • test_〇〇 から始まるメソッド名(または @test アノテーション付き):これが「1つのテスト」として認識されます。
  • setUp():各テストの実行前に毎回呼ばれる初期化処理です。
  • assertSame($期待値, $実際の値):「期待した値と実際の値が一致しているか」を確認します。
  • expectException():「この処理は例外を投げるはずだ」という期待を書けます。

6. phpunit.xml の設定

毎回コマンドで細かいオプションを指定するのは面倒なので、設定ファイルを用意します。

プロジェクト直下に phpunit.xml を作成します。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true">
    <testsuites>
        <testsuite name="Unit Test Suite">
            <directory>tests</directory>
        </testsuite>
    </testsuites>

    <source>
        <include>
            <directory>src</directory>
        </include>
    </source>
</phpunit>
  • bootstrap:Composerのオートロードファイルを読み込む設定です。これがないと App\Calculator などが見つからずエラーになります。
  • testsuite:どのフォルダのテストを実行するかを指定します。
  • colors="true":ターミナルの結果表示をカラフルにしてくれます(見やすくなります)。
  • source > include:カバレッジ計測(後述)の対象フォルダを指定します。

この設定ファイルがあることで、以降は単純に以下のコマンドだけでテストが実行できます。

./vendor/bin/phpunit

7. テストを実行してみる

準備ができたら、実際にテストを実行してみましょう。

./vendor/bin/phpunit

すべて成功した場合、以下のような表示になります。

PHPUnit 10.x by Sebastian Bergmann and contributors.

....                                                               4 / 4 (100%)

Time: 00:00.010, Memory: 6.00 MB

OK (4 tests, 4 assertions)
  • .(ドット)1つが1つのテストの成功を表します。
  • 最後に OK (4 tests, 4 assertions) と表示されれば、すべてのテストが成功(グリーン) した状態です。

7-1. わざと失敗させてみる

「テストが失敗した場合どう見えるか」も体感しておくと安心です。試しに Calculator.phpadd メソッドを壊してみましょう。

public function add(int $a, int $b): int
{
    return $a + $b + 1; // わざとバグを入れる
}

この状態でテストを実行すると、以下のような表示になります。

PHPUnit 10.x by Sebastian Bergmann and contributors.

F...                                                               4 / 4 (100%)

There was 1 failure:

1) Tests\CalculatorTest::test_add_returns_correct_sum
Failed asserting that 4 is identical to 3.

/path/to/tests/CalculatorTest.php:20

FAILURES!
Tests: 4, Assertions: 4, Failures: 1.
  • F は失敗(Failure)を表します。
  • どのテストが、どこで、何を期待していて、実際は何だったのかが明確に表示されます。

これが「テストコードがあると何が嬉しいのか」を体感できる瞬間です。バグを入れた瞬間に、どこで何が壊れたのかが一目瞭然になります。修正が終わったら忘れずに元に戻しておきましょう。


8. よく使うアサーション一覧

「アサーション」とは「〇〇のはずだ、と主張する(確認する)メソッド」のことです。代表的なものをまとめます。

メソッド 意味
assertSame($expected, $actual) 値と型が完全に一致するか(===と同等)
assertEquals($expected, $actual) 値が等しいか(型は緩め、==と同等)
assertTrue($condition) 条件がtrueか
assertFalse($condition) 条件がfalseか
assertNull($value) 値がnullか
assertCount($count, $array) 配列の要素数が一致するか
assertInstanceOf(Class::class, $object) 指定クラスのインスタンスか
expectException(Exception::class) 指定の例外が発生するか
assertStringContainsString($needle, $haystack) 文字列に部分文字列が含まれるか

基本的には assertSame を使う場面が最も多いです。「型まで含めて厳密に一致しているか」を確認できるためです。


9. 「このテストは問題ない」とどうやって判断するのか

ここが今回の記事で一番大事なポイントです。テストコードを書いただけでは意味がなく、「テストが正しく機能しているか」を判断する視点が必要です。

9-1. まずは「グリーンになっているか」

一番シンプルな基準は、OK (n tests, n assertions) という**グリーン(全成功)**の表示が出ているかどうかです。1つでも F(失敗)や E(エラー)が出ていたら、問題ありです。

9-2. わざと壊してみて「ちゃんと落ちるか」を確認する

意外と見落とされがちですが、「テストが通ること」だけでなく「バグを入れたらちゃんとテストが失敗すること」も確認すべきです。

なぜなら、書き方によっては「何をテストしても必ず成功してしまう、意味のないテスト」になってしまうことがあるからです(例:assertTrue(true) だけ書いてしまっているケースなど)。

そのため、テストコードを書いたら一度、本体のコードにわざとバグを入れてみて、**ちゃんとテストが赤くなる(失敗する)**ことを確認する習慣をつけましょう。これを俗に「テストのテスト」と呼んだりします。

9-3. カバレッジ(Coverage)を確認する

カバレッジとは、「本体のコードのうち、どれくらいの割合がテストによって実行されたか」を示す指標です。

カバレッジを計測するには Xdebug または PCOV という拡張機能が必要です。以下のコマンドでインストール状況を確認できます。

php -m | grep -i xdebug

入っていない場合はインストールが必要ですが(環境によって手順が異なるため割愛します)、入っていれば以下のコマンドでカバレッジレポートを取得できます。

./vendor/bin/phpunit --coverage-text

実行結果イメージ:

Code Coverage Report:

 Summary:
  Classes: 100.00% (1/1)
  Methods: 100.00% (3/3)
  Lines:   90.00% (9/10)
  • Classes/Methods/Lines のカバレッジ率が表示されます。
  • 100%が必須というわけではありませんが、重要なロジック(お金の計算、認証処理など)は高いカバレッジを目指すべきです。
  • カバレッジが低い=「テストされていないコードが多い」=「バグが潜んでいる可能性が高い」という目安になります。

HTML形式で見やすくレポート化することもできます。

./vendor/bin/phpunit --coverage-html coverage-report

実行後、coverage-report/index.html をブラウザで開くと、どの行がテストされていないかが色分けされて表示されます。

9-4. CI(継続的インテグレーション)に組み込む

チーム開発では、コードをpushするたびに自動でテストが実行される仕組み(CI)を用意するのが一般的です。GitHub Actionsを使う場合の例を載せておきます。

.github/workflows/phpunit.yml

name: PHPUnit Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'

      - name: Install dependencies
        run: composer install --prefer-dist --no-progress

      - name: Run tests
        run: ./vendor/bin/phpunit

これにより、人間が忘れずにテストを実行する」のではなく「機械的に必ずテストが実行される状態になります。これが「テストコードが問題ないとわかる」ための、最も確実な仕組みです。


10. まとめ

段階 やること
① 理解 テストコードとは「期待通り動くかをプログラムに確認させる仕組み」
② 導入 composer require --dev phpunit/phpunit でインストール
③ 設定 phpunit.xml を用意し、tests フォルダを対象に指定
④ 実装 TestCase を継承し、assertSame などでテストを書く
⑤ 実行 ./vendor/bin/phpunit でグリーンになるか確認
⑥ 検証 わざとバグを入れて赤くなるか確認/カバレッジを計測
⑦ 運用 CIに組み込み、自動でテストが走る仕組みを作る

テストコードは「書いたら終わり」ではなく、「そのテストが本当に意味のあるチェックになっているか」を継続的に見直すことが大切です。今回紹介した「わざと壊してみる」「カバレッジを見る」「CIに乗せる」を実践すれば、初心者の方でも十分に「安心できるテストコード」を書けるようになります。

ぜひ手元の環境で、実際にコマンドを打ちながら試してみてください。


参考リンク

JISOUのメンバー募集中!

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてください!

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?