UnitTestForPlugins

Top > PluginDev > UnitTestForPlugins
Table of Contents
First Edition. May 17 2006.
Last Modified. May 19 2006.

UnitTest for Pukiwiki Plugins - 古い

#Pukiwiki Plus! でテストしているので、この alltest.ini.php は通常の Pukiwiki ではうまくないかもしれないことに後で気づいた。

#新しい alltest.ini.php を用意しなければいけなくなった模様 02/01/2007。非常に面倒くさい。unset さえなければいいわけで。

UnitTest とは

省略。

とりあえず試してみよう

Pukiwikiでやりやすいように、ある程度枠組みを作ってしまいました。

リンクからダウンロードして、上の構成となるように配置してください。 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( "&lt;i&gt;", 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_funccall_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 を使用している場合、実際にページを作らずにテストしたいわけです。 その場合、自分は以下のようにしています。

  1. ../xxx.inc.php? のようにクラス化。クラス PluginXxx を作成し、その中でコードを書く。
  2. PukiWiki API を直接呼ばずに、そのクラス内にAPI関数と同名の関数を用意し、そこから呼ぶようにラッピング。
    function get_existpages()
    {
        return get_existpages();
    }
    少し面倒くさくなるが、プラグイン内では $this->get_existpages(); のように呼ぶようにする。
  3. テスト用ファイルで、require PLUGIN_DIR . 'xxx.inc.php'; をし、テスト用のクラス PluginXxxUnitTest extends PluginXxx を作成
  4. PluginXxxUnitTest 内で function get_existpages() をオーバーライド。ここで適当にページ配列を返す。
  5. テスト用ファイルで define('PLUGIN_UNITTEST', true) を宣言し、プラグイン内でそれにより PluginXxxUnitTest を使用するか PluginXxx を使用するか分岐する。

../xxx.inc.php? では何もオーバーライドする必要がありませんが、テンプレートとして枠組みだけ作ってあるので参考にしてみてください。../contentsx.inc.php?, ../lsx.inc.php? では実際に使用しているのでそれらも参考にしてみてください。

#もっとうまい方法があったら教えてください。

参考


*1 これは PHPUnit のクラス PHPUnit_GUI_SetupDecorator の仕様です。