PHPUnitのテストメソッドに任意の引数を渡す。

PHPUnitのテストメソッドに任意の引数を渡すことができる。

確認に使用したバージョン
PHP:5.6.28
PHPUnit:5.7.0

渡す時は、@dataProviderアノテーションを使う。
このメソッドをデータプロバイダメソッドと呼ぶ。

データプロバイダメソッドを使った、任意の引数を渡すコードは以下の様になる。

use PHPUnit\Framework\TestCase;

class learnTest extends Testcase
{
    /**
     * @dataProvider dataProvider
     */
    public function testAdd($expected, $a, $b)
    {
        $this->assertEquals($expected, $a + $b);
    }

    public function dataProvider()
    {
        return [
            'adding zeros' => [0, 0, 0],
            'zero plus one' => [1, 0, 1],
            'one plus zero' => [1, 1, 0],
            'one plus one' => [2, 1, 1]
        ];
    }
}

testAdd()メソッドに@dataProviderアノテーションを書く。
これにより、dataProvider()から引数を受け取ることができる。

dataProvider()のデータを連想配列にしているのは、エラーが起きたときに、
どのテストデータでエラーが起きたのか表示するのに使うため。

試しに、one plus zeroの$expectedの部分を9に変更して実行する。
すると、以下のメッセージが出力される。


1) learnTest::testAdd with data set "one plus zero" (9, 1, 0)
Failed asserting that 1 matches expected 9.

PHPUnitで複数テストメソッドの依存を設定する

PHPUNitは、@dependsアノテーションを使うことで1つのメソッドに対して、
複数のテストメソッドの依存も表すことが出来る。
コードを書いて確認する。

確認に使用したバージョン
PHP:5.6.28
PHPUnit:5.7.0

書いたコード

use PHPUnit\Framework\TestCase;

class learnTest extends Testcase
{
    public function testProducerFirst()
    {
        $this->assertTrue(true);
        return '3';
    }

    public function testProducerSecond()
    {
        $this->assertTrue(true);
        return '5';
    }

    /**
     * @depends testProducerFirst
     * @depends testProducerSecond
     */
    public function testConsumer()
    {
        $this->assertEquals(
            ['3', '5'],
            func_get_args()
        );
    }
}

testConsumer()に、@dependsを2つ記述する。
それにより、testConsumer()は、testProducerFirst()とtestProducerSecond()に依存することになる。
testConsumer()は、func_get_args()により、2つのテストメソッドの結果を受け取ることができる。

PHPUnitのテストメソッド間の依存性の確認

PHPUNitは、@dependsアノテーションを使うことでテストメソッド間の依存性を表すことが出来る。
コードを書いて確認する。

確認に使用したバージョン
PHP:5.6.28
PHPUnit:5.7.0

書いたコード

use PHPUnit\Framework\TestCase;

class learnTest extends Testcase
{
    public function testGetNumber()
    {
        $number = 8;
        return $number;
    }
    
    /**
     * @depends testGetNumber
     */
    public function testRecieveNumber($number)
    {
        $this->assertEquals(8, $number);
        return $number;
    }
}

testRecieveNumber()に、@dependsを記述する。
それにより、testRecieveNumber()は、testGetNumber()に依存することになる。
testRecieveNumber()は、testGetNumber()の結果を受け取って、テストを実施することができる。

今回、確認するとき、コードを書いていて、エラーが発生した。
原因は、@dependsを書くときに、1行で書いたため、アノテーションとして判断されず、引数を受け取れなかった。

/* @depends testGetNumber */

/*
出力されたエラー
1) learnTest::testRecieveNumber
Missing argument 1 for learnTest::testRecieveNumber()
*/

// 以下の書き方でもNG。最初の/**が/*になっていて、*が1つ足りない。
/*
 * @depends testGetNumber
 */

PHPUnitで配列操作のテストをしてみる。

PHPUnit5.7.0で配列操作のテストをしてみる。
参考にしたドキュメントのテストコード。

use PHPUnit\Framework\TestCase;

class StackTest extends Testcase
{
    public function testPushAndPop()
    {
        $stack = [];
        $this->assertEquals(0, count($stack));

        array_push($stack, 'foo');
        $this->assertEquals('foo', $stack[count($stack) - 1]);
        $this->assertEquals(1, count($stack));

        $this->assertEquals('foo', array_pop($stack));
        $this->assertEquals(0, count($stack));
    }
}

テストを実行する。結果、すべてOKになった。


> phpunit test.php
PHPUnit 5.7.0 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 225 ms, Memory: 2.25MB

OK (1 test, 5 assertions)

試しに、配列の数が1つであることを確認している箇所を2にしてから実行する。
すると、当然だが、エラーが出力された。
2を予想しているところ、1だったこと。
テストコードの13行目で発生したこと。
3つ目のAssertでエラーが起きたこと。
などがわかる。


There was 1 failure:

1) StackTest::testPushAndPop
Failed asserting that 1 matches expected 2.

test.php:13

FAILURES!
Tests: 1, Assertions: 3, Failures: 1.

PHPUnitをWindowsにインストールする。

PHPUnitのやり方を知らないので、勉強するためにインストールする。

手順は、PHPUnitの日本語ドキュメントを参照した。

Composerを使ってインストールする。
Windowsのデスクトップに作成したフォルダに以下を記載したcomposer.jsonを作成する。

{
    "require-dev": {
        "phpunit/phpunit": "6.1.*"
    }
}

その後、コマンドプロンプトから以下のコマンドを実行する。
composer global require "phpunit/phpunit=6.1.0"

実行すると、PHPUnit6.1系は、PHP7が要件なのでインストールに失敗してしまう。


Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for phpunit/phpunit 6.1.0 -> satisfiable by phpunit/phpunit[6.1.0].
    - phpunit/phpunit 6.1.0 requires php ^7.0 -> your PHP version (5.6.28) does not satisfy that requirement.


Installation failed, deleting ./composer.json.

仕方がないので、少し古いバージョンをインストールすることにする。
すると、エラーなくインストールできた。

composer global require "phpunit/phpunit=5.7.0"

最初は、デスクトップ上のフォルダにインストールされると思っていた。
しかし、実行時のログに


Changed current directory to C:/Users/username/AppData/Roaming/Composer

と出力されていた。

なので、上記のフォルダを調べたらPHPUnitがインストールされていた。
コマンドプロンプトから、インストールしたディレクトリでphpunit -vを実行。
無事にPHPUnit5.7.0がインストールできていることを確認できた。


PHPUnit 5.7.0 by Sebastian Bergmann and contributors.

PHPで改行を削除する。

PHPで改行を削除する。
標準入力には改行が入るので、それを削除する。

まずは、以下のコードで標準入力だけを出力する。


$si = fgets(STDIN);
var_dump($si);

/*
Hello Worldを入力した結果

string(13) "Hello World
"
*/

ここで、preg_replaceを用いて改行を削除する。
実行すると、改行が消えていることがわかる。


$si = fgets(STDIN);
$si = preg_replace('/\r\n|\r|\n/', '', $si);
var_dump($si);

/*
Hello Worldを入力した結果

string(11) "Hello World"
*/

PHP 5.6.28で確認した。

PHPのただの配列でforeachする

foreachにて、キーを使うのは連想配列のときだけかと思っていた。
ただの配列もキーが使えるのは知らなかった。


$sample = array('C', 'Java', 'PHP', 'Perl', 'Ruby', 'Python');

foreach($sample as $key  => $value) {
    echo "Key : $key; Value: $value" . PHP_EOL;
}
/*
Key : 0; Value: C
Key : 1; Value: Java
Key : 2; Value: PHP
Key : 3; Value: Perl
Key : 4; Value: Ruby
Key : 5; Value: Python
*/

PHP 5.6.28で確認した。

PHPのforeachの使い方

PHPでループしたいとき、foreachを忘れてしまって調べる時がある。
そのため、簡単なコードを書いて残しておく。

以下のforeachとforの結果は同じ。


$sample = array('C', 'Java', 'PHP', 'Perl', 'Ruby', 'Python');

foreach($sample as $language) {
    echo $language . PHP_EOL;
}

for($i = 0; $i < count($sample); $i++) {
    echo $sample[$i] . PHP_EOL;
}

/*
C
Java
PHP
Perl
Ruby
Python
*/

空配列の時の動作。


$sample = array();

foreach($sample as $language) {
    echo 'foreach' . PHP_EOL;
}

for($i = 0; $i < count($sample); $i++) {
    echo 'for' . PHP_EOL;
}
/*
結果、なにも出力されない。
*/

PHP 5.6.28で確認した。

PHPのsplit()代替関数

split()の代替関数

PHPのsplitは、PHP7.0で削除された。
代替の関数は、以下の3つ。


// 正規表現で文字列を分割する
array preg_split ( string $pattern , string $subject [, int $limit = -1 [, int $flags = 0 ]] )
// 文字列を文字列により分割する
array explode ( string $delimiter , string $string [, int $limit = PHP_INT_MAX ] )
// 文字列を配列に変換する
array str_split ( string $string [, int $split_length = 1 ] )

必須の引数のみ入れた場合と結果


$str = 'Hello, PHP!';

$pregSplitResult = preg_split("/, /", $str);
print_r($pregSplitResult);
/*
Array
(
    [0] => Hello
    [1] => PHP!
)
*/


$exolodeResult = explode(', ', $str);
print_r($exolodeResult);
/*
Array
(
    [0] => Hello
    [1] => PHP!
)
*/

$strSplitResult = str_split($str);
print_r($strSplitResult);
/*
Array
(
    [0] => H
    [1] => e
    [2] => l
    [3] => l
    [4] => o
    [5] => ,
    [6] =>
    [7] => P
    [8] => H
    [9] => P
    [10] => !
)
*/

CakePHP3のControllerとTemplateを使ってHello Worldを表示する。

最初にControllerだけでHello Worldを表示した。
次にTemplateも使ってHello Worldを表示してみる。

インストールしてから修正したファイルは2つ。
src/Controller/HelloController.php


public function index()
{
    $this->autoRender = false;
    echo 'Hello World.';
}

config/routes.php


Router::scope('/', function (RouteBuilder $routes) {
    $routes->connect('/hello', ['controller' => 'Hello', 'action' => 'index']);

HelloController.phpのindex()は、中身を空にする。


public function index()
{
}

次にTemplateを作成する。
src/Template/Hello/index.ctp


<p>Hello World.</p>

この状態にして、http://hostname:port/helloにアクセスする。
結果、Hello World.は表示できた。
でも、CakePHP3のデフォルトのヘッダが付いている。