30代専業主婦の独学エンジニア挑戦ブログ

実務未経験の30歳の専業主婦が独学でエンジニアを目指すブログです

<PHP>FizzBuzzの例外処理とPHPUnitでテストコードを書く

勉強記録

PHPFizzBuzzの例外処理と、PHPUnitで例外のテストコードをどうやって書くのか勉強しました。

例外処理とは

プログラムがエラーを出した時に、処理を中断して別の処理を行うこと。

PHPでの例外処理

throw文

throw new 例外

任意の場所で例外を投げることができる。
例外はExceptionクラス、またはExceptionクラスのサブクラスである必要がある。
(参考サイト)
PHP: 例外 - Manual

try...catch構文

try{
 例外が発生する可能性がある処理
}catch(例外のクラス 変数){
 エラー発生時の処理
}finally{
 例外の有無に関わらず最後に必ず実行される処理
}

tryに書かれた処理の中で例外が起こると、例外が投げられる(throw文)
例外が投げられると、catchで例外が捕捉され、エラー発生時の処理が行われる

FizzBuzz問題で例外処理を行う

今回、FizzBuzz問題における例外処理を書いてみました。
FizzBuzz(フィズバズ)とは、英語圏で行われている言葉遊びの一種だそうですが、このゲームをプログラミングに応用したものが有名です。
・3の倍数でfizz
・5の倍数でbuzz
・両方の倍数でfizzbuzz
・それ以外は整数
を返すコードを書きます。

今回は、1~100までの数字でFizzBuzz問題を行うとし、1~100以外のものの場合例外を投げる処理を書きました。

<?php

function fizzbuzz($i)
{
    if (!(1<=$i && $i<=100)) {
        throw new OutOfBoundsException("1~100までの数字のみ", 999);
    }
    //3の倍数でfizz、5の倍数でbuzz、3と5の両方の倍数でfizzbuzzと表示
    if ($i%3==0 && $i%5==0) {
        return  "fizzbuzz";
    }
    if ($i%3==0) {
        return "fizz";
    }
    if ($i%5==0) {
        return "buzz";
    }

    return $i;
}

最初に1~100ではないものに関しては、throw new OutOfBoundsExceptionで例外を投げています。

テストコードとは

テストコードは、書いたプログラムが想定どうりの動きをしているのかを確認するためのコード。

PHPUnitでテストコードを書く

PHPユニットテストを行うツール。
ユニットテスト単体テスト)とは、クラスや関数などの小さな単位(ユニット)で動作を確認するためのテストのこと。
Laravelには標準搭載されている。

PHPUnitの詳しい使い方は以下のサイトを参考に行いました
qiita.com

FizzBuzz問題のテストコード

<?php

use PHPUnit\Framework\TestCase;

require_once('src/fizzbuzz.php');


class fizzbuzzTest extends TestCase
{
    /**
     * @dataProvider fizzbuzzProvider
     */
    public function testFizzBuzz($i,$expected)
    {
        $this->assertEquals($expected, fizzbuzz($i));
    }

    public function fizzbuzzProvider()
    {
        return[
            [1, 1],
            [2, 2],
            [3, 'fizz'],
            [4, 4],
            [5, 'buzz'],
            [6, 'fizz'],
            [7, 7],
            [8, 8],
            [9, 'fizz'],
            [10, 'buzz'],
            [11, 11],
            [12, 'fizz'],
            [13, 13],
            [14, 14],
            [15, 'fizzbuzz'],
            [16, 16],
            [17, 17],
            [18, 'fizz'],
            [19, 19],
            [20, 'buzz'],
            [21, 'fizz'],
            [22, 22],
            [23, 23],
            [24, 'fizz'],
            [25, 'buzz'],
            [26, 26],
            [27, 'fizz'],
            [28, 28],
            [29, 29],
            [30, 'fizzbuzz'],
            [31, 31],
            [32, 32],
            [33, 'fizz'],
            [34, 34],
            [35, 'buzz'],
            [36, 'fizz'],
            [37, 37],
            [38, 38],
            [39, 'fizz'],
            [40, 'buzz'],
            [41, 41],
            [42, 'fizz'],
            [43, 43],
            [44, 44],
            [45, 'fizzbuzz'],
            [46, 46],
            [47, 47],
            [48, 'fizz'],
            [49, 49],
            [50, 'buzz'],
            [51, 'fizz'],
            [52, 52],
            [53, 53],
            [54, 'fizz'],
            [55, 'buzz'],
            [56, 56],
            [57, 'fizz'],
            [58, 58],
            [59, 59],
            [60, 'fizzbuzz'],
            [61, 61],
            [62, 62],
            [63, 'fizz'],
            [64, 64],
            [65, 'buzz'],
            [66, 'fizz'],
            [67, 67],
            [68, 68],
            [69, 'fizz'],
            [70, 'buzz'],
            [71, 71],
            [72, 'fizz'],
            [73, 73],
            [74, 74],
            [75, 'fizzbuzz'],
            [76, 76],
            [77, 77],
            [78, 'fizz'],
            [79, 79],
            [80, 'buzz'],
            [81, 'fizz'],
            [82, 82],
            [83, 83],
            [84, 'fizz'],
            [85, 'buzz'],
            [86, 86],
            [87, 'fizz'],
            [88, 88],
            [89, 89],
            [90, 'fizzbuzz'],
            [91, 91],
            [92, 92],
            [93, 'fizz'],
            [94, 94],
            [95, 'buzz'],
            [96, 'fizz'],
            [97, 97],
            [98, 98],
            [99, 'fizz'],
            [100, 'buzz'],
        ];
    }

    /**
     * @dataProvider fizzbuzzErrorProvider
     */
    public function testException($i, $e)
    {
        //例外の型をチェック
        $this->expectException(get_class($e));
        //指定したメッセージかチェック
        $this->expectExceptionMessage($e->getMessage());
        //指定したコードかチェック
        $this->expectExceptionCode($e->getCode());

        fizzbuzz($i);
    }

    public function fizzbuzzErrorProvider()
    {
        return[
            [0, new OutOfBoundsException("1~100までの数字のみ",999)],
            [101,new OutOfBoundsException("1~100までの数字のみ",999)],
            [102,new OutOfBoundsException("1~100までの数字のみ",999)],
            ["a",new OutOfBoundsException("1~100までの数字のみ",999)],
            ["あ",new OutOfBoundsException("1~100までの数字のみ",999)],
        ];
    }
}
今回のテストコードのポイント!

・fizzbuzzTestクラスはPHPUnit\Framework\TestCaseクラスを継承する。

require_onceでテスト対象のファイルを読み込んでテストを行う。

・データプロバイダを使用。テストケースに渡すデータのセットを定義できる機能。
テーブルドリブンテストを書くための仕組み。

/**
*@dataProvider データのセットを渡すメソッド名
*/

@dataProviderアノテーションを記述することで、使うことができる。

「テーブルドリブンテスト」とは?
テーブル駆動テストとも言う。
入力と期待値をセットにしてテーブルのように記述していく。
こうすることで、たくさんのデータを同じ処理でテストすることができる。
(テーブルドリブンテストにしないと、データのかたまりがないから処理をたくさん書かなければならない。書き間違える可能性もあるし、読みにくい!)

今回は特に1~100の値について、testFizzBuzzという1個のテストで100個のサブテストを行なっている。