10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PHP Paiza 自動テストテンプレート

Last updated at Posted at 2021-02-12

以前書いた PHP Paiza 標準入力テンプレート の記事が好評でPaizaの問題を解くときに参考にしてますというお声をよくいただいてます。とても嬉しいです☺️

環境

  • PHP: 7.3以上

お悩み相談

Paizaに問題を提出すると標準入力と標準出力の結果を確認されるのですが、毎回手でポチポチ入力例を入力していくのは手間ですよね...?
入力例が1行であれば、まぁいいかとなるんですが、複数行入力するのは割と時間かかっちゃいますし、誤入力やりがちです。

phpunit というPHPの便利なテストフレームワークはありますが、Paizaの問題を解くためにフレームワークを入れるのは、まぁ大掛かりな気持ちがあります。

ということで今回は自前のテストコードを作っていきたいと思います。

FizzBuzz問題

今回はレベルアップ問題集 | PaizaからFizz Buzz (paizaランク C 相当) | Paizaを解いていきます。

整数 N が入力として与えられます。

1からNまでの整数を1から順に表示してください。

ただし、表示しようとしている数値が、

・3の倍数かつ5の倍数のときには、"Fizz Buzz"
・3の倍数のときには、"Fizz"
・5の倍数のときには、"Buzz"

を数値の代わりに表示してください。

入力例1
5

出力例1
1
2
Fizz
4
Buzz
入力例2
20

出力例2
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz Buzz
16
17
Fizz
19
Buzz

FizzBuzz解答例

色々な解き方はあるかと思いますが、私の解答例です。

fizzbuzz.php
<?php declare(strict_types=1);

$input = trim(fgets(STDIN));

for ($i = 1; $i <= $input; $i++) {
    echo fizzBuzz($i), PHP_EOL;
}

function fizzBuzz(int $num): string
{
    return [
        [(string) $num, 'Buzz'],
        ['Fizz', 'Fizz Buzz'],
    ][$num % 3 == 0][$num % 5 == 0];
}

久しぶりにFizzBuzz問題を解きましたが、難しいですね。
何とかかんとか解けましたが、果たしてこのコードは正しいのでしょうか...?
自信がありません...。自動テストさえできれば...

本題: テストコードを用意する

test.php を用意します。

test.php
<?php declare(strict_types=1);

// テストしたいファイルを指定する
$command = 'fizzbuzz.php';

// テストケースを定義する
$patterns = [
    'case1' => [
        'stdin' => ['5'],
        'stdout' => ['1', '2', 'Fizz', '4', 'Buzz'],
    ],
    'case2' => [
        'stdin' => ['20'],
        'stdout' => explode(PHP_EOL, <<<EOD
            1
            2
            Fizz
            4
            Buzz
            Fizz
            7
            8
            Fizz
            Buzz
            11
            Fizz
            13
            14
            Fizz Buzz
            16
            17
            Fizz
            19
            Buzz
            EOD
        ),
    ],
    'case3' => [
        'stdin' => ['3'],
        'stdout' => ['1', '2', 'Fuga'], // わざとテストが落ちるデータを入れてます
    ],
];

foreach ($patterns as $case => $pattern) {
    assertStandard($command, $case, $pattern['stdin'], $pattern['stdout']);
}

function assertStandard(string $command, string $case, array $stdin, array $stdout): void
{
    $args = implode('\\\n', $stdin);
    $actual = trim(`echo $args | php $command`);
    $expected = implode(PHP_EOL, $stdout);

    echo sprintf("%s: %s, stdin: ['%s'], stdout: ['%s'] ... ", $command, $case, implode("', '", $stdin), implode("', '", $stdout));

    try {
        assert($expected === $actual);
        echo 'ok', PHP_EOL;
    } catch (AssertionError $exception) {
        echo 'ng', PHP_EOL, '[actual]', PHP_EOL, $actual, PHP_EOL;
        exit;
    }
}

標準入力と標準出力をテストするため、 echo $args | php $command でphpコード内でphpを実行してます。
バッククォート(実行演算子)で囲むとshell_execと等価です。

$actual には実際のコードの実行結果、$expectedにはテストケースに定義した予期する値を設定してます。
assertメソッドで結果を比較してます。

実際に使う場合は、テストしたいファイル名とテストケースを定義して使ってください。
テストケースは配列で定義する必要があります。標準入力や標準出力の数が多い場合は例のようにヒアドキュメントを使って定義してください。

テストケースは別ファイルから読み込むようにするか悩みましたが、どうだろう...? またご要望あれば検討しようかなと思います。

自動テストを実行する

$ php test.php
fizzbuzz.php: case1, stdin: ['5'], stdout: ['1', '2', 'Fizz', '4', 'Buzz'] ... ok
fizzbuzz.php: case2, stdin: ['20'], stdout: ['1', '2', 'Fizz', '4', 'Buzz', 'Fizz', '7', '8', 'Fizz', 'Buzz', '11', 'Fizz', '13', '14', 'Fizz Buzz', '16', '17', 'Fizz', '19', 'Buzz'] ... ok
fizzbuzz.php: case3, stdin: ['3'], stdout: ['1', '2', 'Fuga'] ... ng
[actual]
1
2
Fizz

テストケース1, 2はちゃんと通ってるのでひと安心ですね☺️
テストケース3はあえて落ちるようにしています。

テストが通った場合は ok
テストが通らなかった場合は ng と実行結果を返すようにしてます。

これでPaizaの問題を解くときの動作確認がラクになるかなと思います!
もしよかったら使ってみてください!

参考

10
8
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
10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?