CodeIgniter3 x PHPUnit で private methodをテストする
privateメソッドのテストは、複雑なデータ構造を扱う時など開発途中で時々どうしても書きたくなります。
その外のpublicのテストでカバーできたら、private のテストは捨てちゃったりしますが。
Rubyだと send 使って何でもできるのに、と思いつつ調べつつPHPでテスト書いてみました。
PHPだと?
PHP5.4時代のprivateメソッドテスト手法 #php5_4: Architect Note
こちらが詳しいのですが
5.3以前だとReflectionMethodを使う方法がありますが、
5.4以降だとClosureが使えます。
5.3のClosureだと$thisが渡せなくて辛い想いを経験したことがありますが
5.4以降で対応してくれたようです。
($thisのcontextを変えれえないのはclosureとしては辛い。。)
Closure::bind を使った例
最近CodeIgniter3 x PHPUnitでテストを書いているので
ちょっと試してみました。
CodeIgniter3 での PHPUnit は kenjis/ci-phpunit-test こちらを利用しています。
関連: CodeIgniter 3 で PHPUnit を使ってテストをする - rochefort's blog
_some_private_method() をテストする例。
<?php class Some_library_test extends TestCase { public function setUp() { $this->CI =& get_instance(); $this->CI->load->library('Some_library'); $this->obj = $this->CI->some_library; } /** * _private_some_method のテスト * * @dataProvider some_provider */ public function test_private_some_method($expected, $param) { $cl = Closure::bind(function($param) { return $this->obj->_some_private_method($param); }, $this, 'Some_library'); $actual = $cl->__invoke($param); $this->assertEquals($expected, $actual); } /** * private_some_method のデータプロバイダ * * @return array [$expected, $params] */ public function some_provider() { return [ ['expected', 'params'], ['expected2', 'params2'] ]; } }
ポイントは、データプロバイダを使うとこです。
関連: PHPUnitいいね - rochefort's blog
こいつを使うことでいろんなデータパターンを利用したテストが(割と)すっきりかけます。
Closure作って __invokeで実行しているのですが
__invoke が引数を取れるので、データプロバイダの値をclosureの中に渡して使えます。
結論
Closureいいね!
See Also
・ CodeIgniter 3 で PHPUnit を使ってテストをする - rochefort's blog
・PHPUnitいいね - rochefort's blog