Yiiの機能テスト(functional test)について

PHPのYiiフレームワークのテストには、「ユニットテスト」と「機能テスト」がある。
このうち、機能テストはSeleniumTestCase.phpを拡張したもので、基本的にセレニウムリモート
コントロール(サーバー)が必要になる。
ということで、サーバ側にfirefoxなどのブラウザを入れる必要があり、ちょっと大がかりだ。GUIを入れてない環境だと使えないし、、、。
もちろん、ブラウザ経由でテストした方がjavascriptなどもテスト出来るのでいいのだが、そこまで
出来なくても簡単なテストだけしたいこともあるだろう、、。

YiiもRuby on Railsに影響を受けたフレームワークであるが、Ruby on Railsのデフォルトテスト
フレームワークでは、ユニットテスト、機能テスト、結合テストの3種類があった。(まあ、RSpec
が便利そうだけど)
RoRの機能テストは、Yiiの機能テストよりかなりシンプルで、get,postの内容を連想配列で送って、
その結果を連想配列で受け取るだけだった。

なので、あの「シンプルな」機能テストがYiiにも欲しいと思い、curlを利用したテストコードを
書いてみた。そのうち、gitに上げたいと思うが、とりあえず短いのでここに記述する。

まずは、CTestCaseを拡張した抽象クラスとしてCResponseTestCase.php


tests/CResponseTestCase.php

$val ) {
array_push($list, urlencode($key) . "=" . urlencode($val) );
}
$string = implode( "&" , $list );
} elseif (is_string($post)) {
$string = $post;
}
$ch = curl_init( RESPONSE_TEST_BASE_URL . $address );
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLINFO_HEADER_OUT,true);
curl_setopt ($ch,CURLOPT_POST,true);
curl_setopt ($ch,CURLOPT_POSTFIELDS,$string);
curl_setopt ($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt ($ch,CURLOPT_RETURNTRANSFER, true);

$c = curl_exec($ch);
$result = curl_getinfo($ch);
$result["html"] = $c;
curl_close($ch);
return $result;

}

}

?>

そして、CResponseTestCase.phpを継承したテストケースの親クラス

tests/ResponseTestCase.php

ResponseTestCase.phpでは、サーバー上からアクセスするためのベースになるURL定数を定義しておく。(これは、おそらく環境ごとに異なると思う)

そして、具体的なテストクラス

tests/functional/SiteTest2.php

getHttp('');
// echo "HTTP_CODE = " . $c["http_code"];
$this->assertTrue( 200 == $c["http_code"]);
}

public function testContact() {
$data = array( "ContactForm[name]" => "hoge" );
// $data = array( "ContactForm[email]" => "hoge" );
$c = $this->postHttp('?r=site/contact' , $data );
$doc = new DOMDocument();
$doc->loadHTML($c["html"]);
$elem = $doc->getElementById("contact-form");
$formtext = $doc->saveHtml($elem); // only php 5.3.6 or higher
$this->assertTrue( preg_match("/Name cannot be blank\./",$formtext) == 0);
$this->assertTrue( preg_match("/Email cannot be blank\./",$formtext) == 1 );
$this->assertTrue( preg_match("/Subject cannot be blank\./",$formtext) == 1 );
$this->assertTrue( preg_match("/Body cannot be blank\./",$formtext) == 1);
$this->assertTrue( preg_match("/The verification code is incorrect\./",$formtext) == 1);
}


}
?>

こんな感じ。

CResponseTestCase.phpで定義されたcurlによるgetHttp,postHttpメソッドを用いてアクセスし、
得た結果はDOMDocumentと正規表現でパースして、assert判定を行っている。

これならかなりシンプルだし、テキストベースの環境でテスト出来るので便利ではないかと思う。

なお、上記のテストがSiteTest2.phpとなっているのは、デフォルトで作成されるSiteTest.php
対応するテストと比較するためです。

p.s.
 書き忘れてましたが、上記はまだfixtureとか出来ません。
 すいません、、。
 fixtureは、CWebTestCaseのコードを真似すればそれほど難しくない(、、、と思う)ので、時間があったら、やります。