躊躇も脈絡も無く、start。
まずはinstall。
gitで引っ張ってこれるので大変においちゃん好み。
適当なディレクトリにおいておきましょう。
clone git://github.com/mlively/Phake.git phake
今回は「phake」ってディレクトリにしておいた。素直というよりは単純。
まず「使える」ようにする。
インストールディレクトリん中のsrcにパスが通ってる必要があるっぽいので、最低限が、こんな感じ。
$dir = "./phake/src/"; set_include_path(get_include_path() . ':' . $dir); require_once('Phake.php');
面倒だからdirは相対パスだけど、本当は絶対パスのほうがよいと思う。
MagicWeaponだと、configのlib_pathに追加する感じかねぇ。
これでもぉ使えるので、試してみる。
<?php $dir = "./phake/src/"; set_include_path(get_include_path() . ':' . $dir); require_once('Phake.php'); class hoge { } $obj = \Phake::mock('hoge'); var_dump($obj);
うん動く。
先に実験「無いメソッドはどなるの?」。
<?php $dir = "./phake/src/"; set_include_path(get_include_path() . ':' . $dir); require_once('Phake.php'); class hoge { } $obj = \Phake::mock('hoge'); //var_dump($obj); $i = $obj->test_method();
ちゃんと「メソッドないズラ」的エラーがでる。
「hogeクラスに」メソッド入れてみる。
<?php $dir = "./phake/src/"; set_include_path(get_include_path() . ':' . $dir); require_once('Phake.php'); class hoge { public function test_method($i = 0) { return 1; } } $obj = \Phake::mock('hoge'); //var_dump($obj); $i = $obj->test_method(); var_dump($i);
ちゃんと「NULL」がreturnされる。
つまり
・メソッドがなけりゃちゃんとエラーが出て
・メソッドがあると、デフォルトでPhakeが吸収する
ことが判明する。
つぎ。んぢゃ「挙動を指定」してみる。
<?php $dir = "./phake/src/"; set_include_path(get_include_path() . ':' . $dir); require_once('Phake.php'); class hoge { public function test_method($i = 0) { return 1; } } $obj = \Phake::mock('hoge'); //var_dump($obj); \Phake::when($obj)->test_method()->thenReturn(1111); $i = $obj->test_method(); var_dump($i);
ちゃんと出る。
引数の指定とかを少しまとめて。
<?php $dir = "./phake/src/"; set_include_path(get_include_path() . ':' . $dir); require_once('Phake.php'); class hoge { public function test_method($i = 0) { return 1; } } $obj = \Phake::mock('hoge'); //var_dump($obj); \Phake::when($obj)->test_method()->thenReturn(1111); \Phake::when($obj)->test_method(1)->thenReturn(1234); \Phake::when($obj)->test_method(9)->thenReturn(9999); $i = $obj->test_method(1); var_dump($i); $i = $obj->test_method(9); var_dump($i); $i = $obj->test_method(); var_dump($i); $i = $obj->test_method(9); var_dump($i);
結果
すばらしい意図通り。
やっぱり興味のある2a問題。
<?php $dir = "./phake/src/"; set_include_path(get_include_path() . ':' . $dir); require_once('Phake.php'); class hoge { public function test_method($i = 0) { return 1; } } $obj = \Phake::mock('hoge'); //var_dump($obj); \Phake::when($obj)->test_method(1)->thenReturn(1234); \Phake::when($obj)->test_method("1")->thenReturn("1234"); $i = $obj->test_method(1); var_dump($i); $i = $obj->test_method("1"); var_dump($i);
結果
…へぇ。若干以外な気もする。ほんのりとはまりそうなので、一応注意。
追加で実験。
\Phake::when($obj)->test_method("1")->thenReturn("1234"); \Phake::when($obj)->test_method(1)->thenReturn(1234);
だと
int(1234)
int(1234)
になる。基本後出し有効か。
…をや? ってことは?
\Phake::when($obj)->test_method("01")->thenReturn("1234"); \Phake::when($obj)->test_method(1)->thenReturn(1234); $i = $obj->test_method(1); var_dump($i); $i = $obj->test_method("01"); var_dump($i);
int(1234)
int(1234)
…違うか。ハッシュ配列にまつわる話かなぁ、って思ったんだが。
これだと?
\Phake::when($obj)->test_method("")->thenReturn("1234"); \Phake::when($obj)->test_method(0)->thenReturn(1234); $i = $obj->test_method(0); var_dump($i); $i = $obj->test_method(""); var_dump($i);
int(1234)
int(1234)
…あや。
もちろんたぶん…
\Phake::when($obj)->test_method(0)->thenReturn(1234); \Phake::when($obj)->test_method("")->thenReturn("1234"); $i = $obj->test_method(0); var_dump($i); $i = $obj->test_method(""); var_dump($i);
string(4) "1234"
string(4) "1234"
だよね。
え?
ってことは…
\Phake::when($obj)->test_method(22)->thenReturn(1234); \Phake::when($obj)->test_method("22a")->thenReturn("1234"); $i = $obj->test_method(22); var_dump($i); $i = $obj->test_method("22a"); var_dump($i);
string(4) "1234"
string(4) "1234"
やぱり orz
もういっちょ。
\Phake::when($obj)->test_method(22)->thenReturn(1234); \Phake::when($obj)->test_method("22a")->thenReturn("1234"); $i = $obj->test_method("22"); var_dump($i); $i = $obj->test_method("22a"); var_dump($i);
int(1234)
string(4) "1234"
予想通り。
実装見てないけど。おそらく、単純に「引数」を内部的に==でチェックしてるんじゃないかなぁ?
んと…まず「引数はとにかく、配列にpushして全部積んである」前提。メソッドがcallされたタイミングで「今渡された引数と、積んである引数予定とをチェック」。beginぢゃなくてrbeginなのはまぁきっとなんかあるんだろう。
そうすると…
・予定している(積んでいる)引数:22, "22a"
の場合、callで22(int)だと
・"22a" == 22 → true
で、文字列が帰ってきちゃう。
一方、callを文字列にしておくと
・"22a" == "22" → false
・"22" == "22" → true
で、ちゃんと見分けがついてる。
たぶん、こんな風なのだろう、と予想。
2a問題って基本的に「片方が数値(int)だと発生する」から。最終的には「ちゃんと型まで見てほしい」んだけど、現状は「すべて文字列にしておく」のが、いったん、回避策になりそう。
…内部で自力で「変数の型に応じて処理を内部でスイッチする」、ポリモーフィズムな実装とかやってるとテスト大変そうだけど。
でもまぁ、SimpleTestでも回避策はあったから、たぶんなんかあるんじゃないかなぁ?
なかったらpull requestしろ、って話だ、たぶんw
とりあえず「準備は出来た」感じかなぁ。
次回は、もうちょっとあちらこちら、たたく予定。「おいちゃんが使う分」程度にレジュメをそろえたいなぁ。