PHPUnitについてのセッションということで気合い充分で参加してきました。
この8時間耐久シリーズはノマドのなかのノマドであり、安藤の中の安藤である@yandoさんが、無償で行っているセミナー(?)です。
コワーキングスペースのなかのコワーキングスペースである下北沢オープンソースカフェにて、午前中から夕方まで、みっちりPHPUnitについて学んできました。
PHPUnit使ってますか?
普段テストを書いていないとは言えませんが、胸を張って言えるレベルではないわたし。
独習でやってきていると基礎体力の点で充分とは言えないもの。今回はみっちりと筋トレしてこようと思い参加した次第。
午前中はPHPUnitのインストールが中心。
しかしそこはサービス精神旺盛の@yandoさん、普通にインストールするだけではありません。
PyrusというPEARの環境を整えるソフトの説明とそれを利用するメリットも教えてくれます。
わたしが理解したところによると、PEARでいろいろinstallしようとすると、全ユーザーに影響する形でインストールされてしまうという問題があるそうです。
自分の環境のみで特定のバージョンのPEARを使用したいといった場合など、普通にPEARを使用すると生じる問題を解決してくれるナイスなツールですね。
午後からいよいよ本格的にテストについてのお話。
まず簡単なclassのファイルを見て、それに対しテストを書いていきます。
基本的なPHPUnitによるテストの書き方は
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
# tests/SampleTest.php | |
require __DIR__ . '/../lib/Sample.php'; | |
class SampleTest extends PHPUnit_Framework_TestCase { | |
public function testAnyMethod() { | |
$this->object = new Sample(); | |
$this->assertEquals('正しい値', $this->Sample->anyMethod(), 'テストが失敗されたときに表示されるコメント'); | |
} | |
} |
という具合。
これでSmapleクラスのanyMethod()メソッドが実行され、期待する値(ここでは'正しい値')と比較されます。
assartEquals()というアサーションは == を用いた比較をおこない、同値であればめでたくpassedとなります。
実行は、コマンドラインから次のように行います。
$ phpunit tests/Sample.php
ちなみにこうすると、結果が緑(赤)のバーで表示され見やすくなります。
$ phpunit --colors tests/Sample.php
テストに失敗した場合は、失敗したというメッセージとともに「最後の引数で与えたコメント」が表示されます。複数のテストを書く場合に分かりやすくなりますね。
その後さまざまなアサーションの種類を教えてもらいました。バージョンアップのたびに増殖中とのこと。
$this->assertCount()とか。
また setUp() と tearDown() を利用して、共通処理の説明も。
上記のサンプルであれば。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
# tests/SampleTest.php | |
require __DIR__ . '/../lib/Sample.php'; | |
class SampleTest extends PHPUnit_Framework_TestCase { | |
public function setUp() { | |
$this->object = new Sample(); | |
} | |
public function tearDown() { | |
unset($this->object); | |
} | |
public function testAnyMethod() { | |
$this->assertEquals('正しい値', $this->Sample->anyMethod(), 'テストが失敗されたときに表示されるコメント'); | |
} | |
} |
という具合。これでテストメソッドがtestOther(), testAnother()のように増えていってもそれぞれのメソッド内でいちいちインスタンスを生成するという重複が避けられます。DRYですね。
ちなみにtearDown()の 'tear' は、涙の「ティア」ではなく、破るという意味の「テア」だそうです。
tear down で「建物等を取り壊す」という意味になるそう。
いやあ勉強になります。こんなこと自分で勉強してたら絶対に分からないですからね。
(この後、休憩中にmacのsayコマンドでいろいろ発音させて遊びました)
その後聞いたことも無い機能を次々と教えてもらいました。
まずはアノテーション。
テストメソッドの前に、指定された内容を書くことで、テストの実行を制限したり、特殊なテストを実行できるようになるとのこと。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
# tests/SampleTest.php | |
require __DIR__ . '/../lib/Sample.php'; | |
class SampleTest extends PHPUnit_Framework_TestCase { | |
public function setUp() { | |
$this->object = new Sample(); | |
} | |
public function tearDown() { | |
unset($this->object); | |
} | |
/** | |
* @group regression | |
* @group bug2204 | |
*/ | |
public function testAnyMethod() { | |
$this->assertEquals('正しい値', $this->Sample->anyMethod(), 'テストが失敗されたときに表示されるコメント'); | |
} | |
} | |
// $ phpunit --group bug2204 |
他にもこんなアノテーションも。かなりDRYに記述できますね。(テストについてはDRYすぎるのも善し悪しだと思いますが、こういうのであれば何をテストしているかも分かりやすく活用したいところです)
続いて、PHPUnitが行う気の利いた機能。
なんとPHPUnitではテスト実行前にスーパーグローバル変数を退避させ、テスト実行後に書き戻してくれるのです!
テストケース内で書き換えても影響は無いんだそう。毎度setUp()とtearDown()で $this->_session = $_SESSION; して $_SESSION = $this->_session; する必要はまったくないんだって。驚愕です。
で、ふと気になって、CakePHPのConfigure::read()できる設定はどうなんだろうと、CakePHPのソースを見てみると!
案の定、同じように処理をしていました。
これは便利すぎますね。
この会では、実際に手を動かして何も無いところからテストを書いていったり、逆にテストが与えられclassを作っていくというプチテスト駆動開発を体験できたりと、非常に盛りだくさんの内容でした。
というわけでまた血になり肉になったようです。
@yando さんどうもありがとうございました!