Espérance: BDD style assertion library for PHP
Espérance という BDD っぽくアサーションを行うライブラリを書いています。
とりあえず PHPUnit の中で使ってみるイメージはこんな感じです。
あと、前に中途半端に作った xSpec フレームワーク Speciphy と組み合わせるとこんなイメージにもできそうです。 (まだ作ってませんが)
なんで should でなく expect なのか
RSpec 3 からは expect がデフォルトになる、という記事が先日ありました。
RSpec's New Expectation Syntax
RSpec といえば "foo".should == "foo" といった具合に、全てのオブジェクトに should メソッドを生やしての アサーション (エクスペクステーション) が特徴でしたが、やっぱり Kernel モジュールに勝手にオブジェクト足されるのは気持ち悪いよね、ということで古き良き Test::Unit を使い続ける人も一定数いるように思われます。
should と比較して、expect は RSpec コンテキスト (多分 ExampleGroup とか Example とかの中だろうけど特に読んではいません) の中に存在するメソッドなのでグローバル空間に副作用がありませんし、それでいて英語としても読み下しやすい DSL だと言えます。
そして expect といえば、JavaScript の BDD ライブラリでは結構ベタだったりします。
Jasmine もそうですし、Socket.IO の作者による expect.js というものもあります。
Espérance は expect.js を PHP に移植して作っています。
PHPSpec について
PHP はオープンクラスでないので、全てのオブジェクトに should メソッドを生やす、なんてことはできません。
そこで PHPSpec では $this->spec("foo") とすることで、値を Interceptor オブジェクトでラップし、Interceptor がマジカルな DSL を実現する、という作りになっています。
PHPSpec の Interceptor は独立したライブラリではありませんが、Speciphy でも拝借しており、独立性の高いモジュールでもあります。
PHPSpec の Interceptor は凄いんですが、正直言って頑張り過ぎなんではないかと思っています。
PHPSpec 本体の spec を見ていると $this->matcher->getDescription()->should->be('be equal to 1'); なんてことをしていたりします。
$this->expect($this->matcher->getDescription())->to->be('be equal to 1'); とかで充分やん、とか思ってしまうわけです。
とはいえ Espérance も __get とか __call とか使ってますし、マジカルであることに変わりはないのですが、作りは大分シンプルになっていると思います。
expect.js の実装を真似ているので、expect.js が凄いというだけの話でもあるのですが。
expect.js の DSL の実装について
ところで expect.js では expect(1).to.be(1) といったプロパティのチェーンを、Assertion オブジェクトを再帰的に生成して to プロパティに新しい Assertion を差し込む、なんてことをしており、一度 expect(1) としただけで 40 数回ぐらいコンストラクタが呼ばれるています。
PHP では __call でプロパティ読み出しをオーバーライドすることができるので、Espérance では再帰的なコンストラクタは行われません。
JavaScript でも最近の処理形だと Object.defineProperty() とかで似たようなことができるような気がするのですが、それをしないのはより幅広い環境での使えるようにということなんでしょうか。 (JavaScript あんまり知らないのでよくわかりません)
名前について
Google 翻訳に expectation と入力してフランス語として出てきた単語から適当に選びました。
フランス語を名前として使うアイディアは、最近話題になった React (通称 node.php) でも使われているイベントディスパッチャライブラリ Événement のパクリです。
今後について
Speciphy もそうですが、ボクはライブラリやフレームワークを作ってもメンテが続かないタイプの人間だということだけ書いておきます。
でもまぁこういう感じでアサーションだけがライブラリと独立しているのは割とありなんじゃないかなーとは思いますし、Packagist への登録ぐらいはやっておきたいと思っています。思っているだけですが。
というわけでレバ刺しを食べに行きます。