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のコードを真似すればそれほど難しくない(、、、と思う)ので、時間があったら、やります。