UnitTestForPlugins
Table of Contents |
Last Modified. May 19 2006.
UnitTest for Pukiwiki Plugins - 古い
#Pukiwiki Plus! でテストしているので、この alltest.ini.php は通常の Pukiwiki ではうまくないかもしれないことに後で気づいた。
#新しい alltest.ini.php を用意しなければいけなくなった模様 02/01/2007。非常に面倒くさい。unset さえなければいいわけで。
UnitTest とは
省略。
とりあえず試してみよう
Pukiwikiでやりやすいように、ある程度枠組みを作ってしまいました。
- index.php (pukiwiki.php)
- pukiwiki.ini.php
- plugin/
alltest.php
alltest.ini.php
- test/
- PHPUnit.php
- PHPUnit/
リンクからダウンロードして、上の構成となるように配置してください。
PHPUnit は本家 http://pear.php.net/package/PHPUnit2/download からダウンロードしてください。
ブラウザから http://YourPukiwikiURL/alltest.php のようにアクセスし、hoge をチェックし、テストを走らせてみましょう。動けばとりあえずOKです。動かなければ・・・わかりません。
御分かりの通り、追加する場合は、plugin ディレクトリにプラグインを、 test ディレクトリにテストコードをおいていってください。
テストコードの作り方
まず、プラグインフォルダにプラグインをおきます。 以下のような hoge.inc.php だとします。
<?php function plugin_hoge_convert() { $args = func_get_args(); return array_pop($args); // last argument } function plugin_hoge_inline() { $args = func_get_args(); return array_pop($args); // {} is being sanitized (htmlspecialchars). } ?>
次に test ディレクトリにテストコードをおきます。 以下のような hoge.php かもしれません。
<?php require_once 'PHPUnit.php'; class test_hoge extends PHPUnit_TestCase { function test_hoge($name) { $this->PHPUnit_TestCase($name); } function setUp() { } function tearDown() { } function test_exist() { $this->assertTrue( exist_plugin('hoge') ); } function test_exist_convert() { $this->assertTrue( exist_plugin_convert('hoge') ); } function test_exist_inline() { $this->assertTrue( exist_plugin_inline('hoge') ); } function test_convert() { $lines = array(); $lines[] = '#hoge(a,b,<i>)'; $this->assertEquals( "<i>\n", convert_html( $lines ) ); $lines = array(); $lines[] = '#hoge(a,b){{'; $lines[] = '<i>'; $lines[] = '}}'; $this->assertEquals( "<i>\r\n", convert_html( $lines ) ); $this->assertRegExp( "/<i>/", convert_html( $lines ) ); } function test_inline() { $string = '&hoge(a,b){<i>};'; $this->assertEquals( "<i>", make_link( $string ) ); } } ?>
クラス名は test_hoge (ディレクトリ名_ファイル名) にしなければいけません*1。
UnitCase 経験者の方はなんとなくわかると思います。真似で書いてみてください。
PHPUnit の説明は端折るので、
本家のドキュメント PHPUnit Pocket Guide を参照してください。
一応少しばかりソースコードの説明をしておきますと、Pukiwiki の関数、 lib/plugin#exist_plugin はプラグインの存在確認とともにプラグインの require を行います。 なので require は書いていません。convert_html は Pukiwiki のWiki文法をHTMLに変換するエンジンです。make_link は [[]] なリンクやインラインプラグインを変換します。convert_html は内部でこれを使用しています。
convert のほうで \n だったり \r\n だったりしていますが、よくわかっていません。 プラグインもテストコードも改行コードは \n (LF) にしているのですが。 テスト環境は Pukiwiki Plus i18n (UTF-8) on apache on Windows なのですが、\r\n を出力したりすることもあるのでしょうか? 適当に改行コードは合わせてみてください。
- 一言:Pukiwiki プラグインは最終的に HTML コードを出力したいわけですが、HTML コードのテストはし辛いですよね。
- 二言:UnitTest のコツは先にテストを書いてそれにより仕様を決め、その後本体のコーディングをすることです。本当は。
- 三言:プラグイン内で定義した関数を呼ぶ場合は call_user_func
や call_user_func_array
が役に立つかもしれません。
UnitTest 実行スクリプト
UnitTest を実行する alltest.php の内容は以下のようになっています。
<?php require 'alltest.ini.php'; define('TEST_DIR', 'test/'); require_once 'PHPUnit/GUI/HTML.php'; require_once 'PHPUnit/GUI/SetupDecorator.php'; $gui = new PHPUnit_GUI_SetupDecorator(new PHPUnit_GUI_HTML()); $gui->getSuitesFromDir(TEST_DIR, '.*.php$'); $gui->show(); ?>
このプログラムは UnitTest の HTML GUI を提供します。 alltest.ini.php で Pukiwiki の定数、関数を読み込むように初期化しています。
alltest.php と同じ階層に 'test/' ディレクトリを作成し、その中にテストファイルを置くと、 自動で読み込んでくれます。 この際、ファイル名が xxx.php なら、クラス名を test_xxx と作成しなければいけないようです。 PHPUnit_GUI_SetupDecorator の仕様、もとい PEAR 準拠らしいです。
Pukiwiki 定数、関数の読み込み
Pukiwiki 定数、関数の読み込みをする alltest.ini.php を作成しました。
非常にやりにくかったです。
Pukiwiki は index.php 内、またそこから読み込んでいる lib/pukiwiki.php 内でも定数を設定していますが、 そのまま、require 'index.php'; としては pukiwiki 自体が実行されてしまうので、実行部分は端折った定数宣言部分だけをコピーする必要があります。
そうして、lib/pukiwiki.php を辿っていくと、その内部で lib/init.php を require しています。 これが曲者で、いくつかの環境変数を unset しているので、PHPUnit_GUI_HTML が正常動作しなくなります。 なので lib/init.php をコピーし、unset を片っ端からコメントアウトしています。
とりあえず動いているように見えます。
#Pukiwiki Plus のコードを改変したので、Plus 用になっています。本家用は自分が使わないので誰か・・・
PukiWiki API のオーバーライド
例えば ../lsx.inc.php? のように PukiWiki API関数、 lib/file.php#get_existpages を使用している場合、実際にページを作らずにテストしたいわけです。 その場合、自分は以下のようにしています。
- ../xxx.inc.php? のようにクラス化。クラス PluginXxx を作成し、その中でコードを書く。
- PukiWiki API を直接呼ばずに、そのクラス内にAPI関数と同名の関数を用意し、そこから呼ぶようにラッピング。
function get_existpages() { return get_existpages(); }
少し面倒くさくなるが、プラグイン内では $this->get_existpages(); のように呼ぶようにする。 - テスト用ファイルで、require PLUGIN_DIR . 'xxx.inc.php'; をし、テスト用のクラス PluginXxxUnitTest extends PluginXxx を作成
- PluginXxxUnitTest 内で function get_existpages() をオーバーライド。ここで適当にページ配列を返す。
- テスト用ファイルで define('PLUGIN_UNITTEST', true) を宣言し、プラグイン内でそれにより PluginXxxUnitTest を使用するか PluginXxx を使用するか分岐する。
../xxx.inc.php? では何もオーバーライドする必要がありませんが、テンプレートとして枠組みだけ作ってあるので参考にしてみてください。../contentsx.inc.php?, ../lsx.inc.php? では実際に使用しているのでそれらも参考にしてみてください。
#もっとうまい方法があったら教えてください。
参考
- http://www.phpunit.de/wiki/Main_Page
PHPUnit本家
- dev:UnitTest
- dev:BugTrack2/113
テスト関連
- dev:BugTrack2/162
プラグインのUnitTest
- dev:BugTrack2/113
- PHPUnitをPukiWikiのプラグインでも使ってみよう!-okkezのPukiWiki