Nette Tester をはじめる

よいプログラマーでも間違えます。よいプログラマーと悪いプログラマーの違いは、よいプログラマーは同じ間違いを一度しかせず、次からは自動のテストでそれを見つけることです。

  • 「テストしない者は、自らの過ちを繰り返す運命にある。」(ことわざ)
  • 「ひとつのエラーを取り除いたとたん、別のエラーが現れる。」(マーフィーの法則)
  • 「print の文を書きたくなったら、代わりにテストとして書け。」(Martin Fowler)

PHP でこんなコードを書いたことはありませんか。

$obj = new MyClass;
$result = $obj->process($input);

var_dump($result);

つまり、関数の呼び出しの結果が思ったとおりのものかを目で確かめるためだけに、それを出力したことはありませんか。おそらく毎日何度もしているでしょう。胸に手を当ててみてください。すべて正しく動いたら、このコードを消しますか。そのクラスがこの先も壊れないと思っていますか。マーフィーの法則はその逆を保証します :-)

要するに、あなたはテストを書いたのです。目で確かめる代わりに自分で確かめるように、少し手を入れればよいだけです。そしてそのテストを消さなければ、この先いつでも走らせて、すべてが今も思ったとおりに動くかを確かめられます。時が経てばそうしたテストがたくさんできるので、それらを自動的に走らせられると便利です。

そのすべてを Nette Tester が助けてくれます。

Tester を他にないものにしているのは何か

Nette Tester のテストを書くことが他にないのは、それぞれのテストがふつうの PHP のスクリプトで、単独で走らせられるところです。

ですからテストを書いたら、そのまま走らせて、たとえばプログラムの間違いがあるかどうかを確かめられます。正しく動くかどうかもです。動かなければ、IDE で簡単に一歩ずつたどって不具合を探せます。ブラウザで開くことさえできます。

そして何より、走らせることがそのままテストの実行になります。通ったか落ちたかがすぐ分かります。どのようにでしょうか。お見せしましょう。PHP の配列を扱うごく簡単なテストを書いて、ArrayTest.php というファイルに保存します。

<?php
use Tester\Assert;

require __DIR__ . '/vendor/autoload.php';  # Composer のオートローダーを読み込みます
Tester\Environment::setup();               # Nette Tester を準備します

$stack = [];
Assert::same(0, count($stack));   # count() が 0 を返すことを期待します

$stack[] = 'foo';
Assert::same(1, count($stack));   # count() が 1 を返すことを期待します
Assert::contains('foo', $stack);  # $stack に 'foo' の要素が含まれるかを確かめます

ご覧のとおり、Assert::same() のようないわゆるアサーションのメソッドを使って、実際の値が期待した値と一致することを確かめます。

テストが書けたので、コマンドラインから走らせられます。最初の実行で構文の間違いがあれば分かりますし、どこも打ち間違えていなければ次のように出力されます。

$ php ArrayTest.php

OK

テストのアサーションを Assert::contains('XXX', $stack); のような誤ったものに変えて、走らせたときに何が起きるか見てみてください。

$ php ArrayTest.php

Failed: ['foo'] should contain 'XXX'

in ArrayTest.php(17) Assert::contains('XXX', $stack);

FAILURE

テストの書き方の話はテストの書き方の章で続けます。

インストールと要件

Tester が求める PHP の最小のバージョンは 8.0 です(詳しくは表 対応している PHP のバージョンをご覧ください)。おすすめのインストールの方法は Composerです。

composer require --dev nette/tester

Nette Tester をコマンドラインから走らせてみてください(引数なしならヘルプだけを出力します)。

vendor/bin/tester

テストの実行

アプリケーションが育つにつれ、テストの数も増えていきます。テストをひとつずつ走らせるのは現実的ではありません。ですから Tester にはまとめてテストを走らせる実行器があり、コマンドラインから呼びます。パラメータにはテストの置かれたディレクトリを指定します。ドットは現在のディレクトリを表します。

vendor/bin/tester .

実行器は指定されたディレクトリとそのすべての下位のディレクトリを探し、*.phpt*Test.php のファイルをテストとして見つけます。私たちのテスト ArrayTest.php も、この形に合うので見つかります。

そしてテストを始めます。それぞれのテストは新しい PHP のプロセスとして走るので、ほかのテストからまったく切り離されて動きます。複数のスレッドで並行して走らせるので、きわめて速く終わります。しかも前回の実行で落ちたテストを最初に走らせるので、不具合を直せたかどうかがすぐに分かります。

テストの実行中、Tester は結果を文字として端末に次々と出力します。

  • . – テストが通った
  • s – テストが飛ばされた
  • F – テストが落ちた

出力は次のようになります。

 _____ ___  ___ _____ ___  ___
|_   _/ __)( __/_   _/ __)| _ )
  |_| \___ /___) |_| \___ |_|_\  v2.6.0

PHP 8.5.2 (cli) | php | 8 threads

........s................F.........

-- FAILED: greeting.phpt
   Failed: 'Hello John' should be
       ... 'Hello Peter'

   in greeting.phpt(19) Assert::same('Hello Peter', $o->say('John'));

FAILURES! (35 tests, 1 failures, 1 skipped, 1.7 seconds)

35 個のテストが走り、ひとつが落ち、ひとつが飛ばされました。

話はテストの実行の章で続けます。

監視モード

コードを整理し直しているところですか。あるいは TDD(テスト駆動開発)の方法論に沿って開発していますか。それなら監視モードが気に入るはずです。このモードでは、Tester がソースコードを見張り、変わったら自動的に自分を走らせます。

開発のあいだ、モニタの隅の端末で緑色の状態の帯が光っていて、それが急に赤くなったら、たった今あまりよくないことをしたと分かります。これはプログラムしながら色を保とうとする、なかなか楽しいゲームです。

監視モードは --watchのパラメータで始めます。

コードカバレッジの報告

Tester は、テストがソースコードをどれだけ覆っているかの概観を報告として生成できます。報告は人が読める HTML の形式でも、機械での処理に向いた Clover XML でも作れます。

コードカバレッジの HTML の報告の例 をご覧ください。

対応している PHP のバージョン

バージョン 対応する PHP
Tester 2.6 PHP 8.0 – 8.5
Tester 2.5 PHP 8.0 – 8.5
Tester 2.4 PHP 7.2 – 8.2
Tester 2.3 PHP 7.1 – 8.0
Tester 2.1 – 2.2 PHP 7.1 – 7.3
Tester 2.0 PHP 5.6 – 7.3
Tester 1.7 PHP 5.3 – 7.3 + HHVM 3.3+
Tester 1.6 PHP 5.3 – 7.0 + HHVM
Tester 1.3 – 1.5 PHP 5.3 – 5.6 + HHVM
Tester 0.9 – 1.2 PHP 5.3 – 5.6

最新のパッチのバージョンに当てはまります。

バージョン 1.7 までの Tester は HHVM 3.3.0 以上にも対応していました(tester -p hhvm で)。この対応は Tester のバージョン 2.0 から打ち切られました。