Ethna 2.5.0 preview2のテストがてらsimpletestを本腰を入れて使ってみた。
ActionClassとActionFormのテストは比較楽に出来たんだけど、AppManagerのテストする時に躓いた。
これをわかっていないといろいろ面倒なので、整理してメモしておこうと思う。
あまりsimpletestのガッツリとした例を見たことが無いのでなんともいえないけど、一つのテストケースクラスで何度もテストを実施するっていのが通常の使い方のように思う。
こんな感じ。
AppObjectのexportFormとか頻繁に使っていたので、ActionForm($this->af)が結構重要な役割を占めていた僕としては、テストの中でも$this->afを使いたいと思っていた。
で、EthnaのUnitTestCaseクラスのソースを見てみても、そうやって使ってもらおう為にいろいろ用意してくれている感じもしたし。
素直に使おうと思ってはみたもののAppManagerクラスのテストは特にどのActionFormクラスを使えば良いというのも無いんだよな。
どうしようかなとソースを見てみると、便利そうなcreatePlainActionForm()って関数があった。
どうやら空のActionFormを作ってくれるみたいなので、これを使うことにした。
あとAppManagerクラスのテストとなると、何度もAppManagerを呼ばないとテストにならないわけで、そんならコンストラクタで呼べばええのかなと思ったんだけど、この辺がなかなか難しい。
結論をいうと、setUpで呼ぶことにした。
ということで、僕のsetUpとtearDownはこんな感じになった。
まずは最初の2行。
セッションをスタートさせているのは、AppManagerクラスで使っているところがある為、使ってない人はいらない。
あと、createPlainActionFormでプレーンなActionFormクラスを生成&エラー周りのデータもクリアしている。
このクリアしているってことを、ちゃんと把握することに時間がかかった。
で、次。
一番のポイントはここ!
特に後の2行、これかなり重要。
というのも、先ほどcreatePlainActionFormで値をクリアしているといったが、それはこのUnitTestCase内のActionFormだけで、AppManagerクラスやAppObjectクラスのデータはクリアされないことがわかった。
つまり
となってしまうんだよね。
ソースを見る限り、参照渡しをしているからAppManager側もクリアされても良いもんだと思うんだけど、実際はされていない模様。
いろいろ調べてみたら、AppManagerクラスやAppObjectクラスは、1回のリクエストの間に何度も呼ばれた場合、2回目以降は1回目呼ばれた時に生成したキャッシュの値を持ってくる仕組みになっているっぽい。
で、実際動かしてみると、1回目のテスト(例えば今回だとfunction test_a)まではちゃんと同期は取れているんだけど、2回目から途端に駄目になり、1回目のActionFormの値がAppMnager側には残ってしまう状態になってしまってる。
多分、クリアの仕方に何か原因がありそうなんだけど、そこまでは追いきれなかった。
ううう。
ということで、解決策としては、setUp()毎にcreatePlainActionForm()やcreateActionForm()を呼んで、その度にActionFormがクリアされたものとしたい場合は、その都度コピーしないといけないってことになる。
で、それがこの部分というわけ。
ふぅ・・・。
後から読み直して自分でも理解できるだろうか・・・。
後の部分は、毎回同じデータがDBにあるという前提でテストをしたいから、毎回テストデータを追加&削除を行っているだけ。
これで、
・毎回ActionFormの値はクリアされている
・DBにも同じデータが入っている
・通常の運用と同じようにActionFormの値がAppManagerクラスにもちゃんと引き継がれる
・AppManagerクラスで変更した場合でも、ちゃんとActionClass(ここではUnitTestCaseクラス)にも反映されて返ってくる
という状態になるので、初めての人でもそんなに違和感無く出来るのでは?と思う。
少なくとも僕はやりやすくなったんだけど。
非常に負荷のかかるやり方をしてしまってはいるとは思うんだけど、その分頭の中はすっきり整理出来るし、今のところはこれで良いのかなと思ってる。
このやり方で何度かテストを行ってるけど、そんなに大きな問題もないし。
まあ、全部のテストを一気にやると、なかなかレスポンスが返ってこなくなっちゃうってことぐらいかな。
この例は特に参考にするもの無く、自分でこんな感じかな?と思って手探りでやった結果なので、正しいやり方じゃないかもしれないけど、あまりネット上にもEthnaでのsimpletestの実例自体が見ないし、特にAppManagerクラスのテストとなると見たことが無かったので晒してみた。
参考になれば是幸い。
ActionClassとActionFormのテストは比較楽に出来たんだけど、AppManagerのテストする時に躓いた。
これをわかっていないといろいろ面倒なので、整理してメモしておこうと思う。
あまりsimpletestのガッツリとした例を見たことが無いのでなんともいえないけど、一つのテストケースクラスで何度もテストを実施するっていのが通常の使い方のように思う。
function test_a()
{
}
function test_b()
{
}
function test_c()
{
}こんな感じ。
AppObjectのexportFormとか頻繁に使っていたので、ActionForm($this->af)が結構重要な役割を占めていた僕としては、テストの中でも$this->afを使いたいと思っていた。
で、EthnaのUnitTestCaseクラスのソースを見てみても、そうやって使ってもらおう為にいろいろ用意してくれている感じもしたし。
素直に使おうと思ってはみたもののAppManagerクラスのテストは特にどのActionFormクラスを使えば良いというのも無いんだよな。
どうしようかなとソースを見てみると、便利そうなcreatePlainActionForm()って関数があった。
どうやら空のActionFormを作ってくれるみたいなので、これを使うことにした。
あとAppManagerクラスのテストとなると、何度もAppManagerを呼ばないとテストにならないわけで、そんならコンストラクタで呼べばええのかなと思ったんだけど、この辺がなかなか難しい。
結論をいうと、setUpで呼ぶことにした。
ということで、僕のsetUpとtearDownはこんな感じになった。
var $um;
var $testdata;
/**
* initialize test.
*
* @access public
*/
function setUp()
{
$this->session->start(); // start session.
$this->createPlainActionForm(); // create ActionForm
// get manager
$this->um =& $this->backend->getManager('Users');
$this->um->action_form =& $this->af;
$this->um->af =& $this->af;
// add test user
$this->af->set('id', 100);
$this->af->set('email', 'hoge@hoge.com');
$this->af->set('password', 'abcde');
$this->af->set('role', 'general');
// add test data
$this->um->addData();
// copy test data
$this->testdata['users'] = $this->af->getArray();
// form data clear
$this->af->clearFormVars();
}
/**
* clean up testcase.
*
* @access public
*/
function tearDown()
{
$this->session->destroy(); // destroy session.
// delete test user
$this->um->deleteData($this->testdata['users']['id']);
}まずは最初の2行。
$this->session->start(); // start session.
$this->createPlainActionForm(); // create ActionFormセッションをスタートさせているのは、AppManagerクラスで使っているところがある為、使ってない人はいらない。
あと、createPlainActionFormでプレーンなActionFormクラスを生成&エラー周りのデータもクリアしている。
このクリアしているってことを、ちゃんと把握することに時間がかかった。
で、次。
$this->um =& $this->backend->getManager('Users');
$this->um->action_form =& $this->af;
$this->um->af =& $this->af;一番のポイントはここ!
特に後の2行、これかなり重要。
というのも、先ほどcreatePlainActionFormで値をクリアしているといったが、それはこのUnitTestCase内のActionFormだけで、AppManagerクラスやAppObjectクラスのデータはクリアされないことがわかった。
つまり
$this->af !== $this->um->afとなってしまうんだよね。
ソースを見る限り、参照渡しをしているからAppManager側もクリアされても良いもんだと思うんだけど、実際はされていない模様。
いろいろ調べてみたら、AppManagerクラスやAppObjectクラスは、1回のリクエストの間に何度も呼ばれた場合、2回目以降は1回目呼ばれた時に生成したキャッシュの値を持ってくる仕組みになっているっぽい。
で、実際動かしてみると、1回目のテスト(例えば今回だとfunction test_a)まではちゃんと同期は取れているんだけど、2回目から途端に駄目になり、1回目のActionFormの値がAppMnager側には残ってしまう状態になってしまってる。
多分、クリアの仕方に何か原因がありそうなんだけど、そこまでは追いきれなかった。
ううう。
ということで、解決策としては、setUp()毎にcreatePlainActionForm()やcreateActionForm()を呼んで、その度にActionFormがクリアされたものとしたい場合は、その都度コピーしないといけないってことになる。
で、それがこの部分というわけ。
ふぅ・・・。
後から読み直して自分でも理解できるだろうか・・・。
後の部分は、毎回同じデータがDBにあるという前提でテストをしたいから、毎回テストデータを追加&削除を行っているだけ。
これで、
・毎回ActionFormの値はクリアされている
・DBにも同じデータが入っている
・通常の運用と同じようにActionFormの値がAppManagerクラスにもちゃんと引き継がれる
・AppManagerクラスで変更した場合でも、ちゃんとActionClass(ここではUnitTestCaseクラス)にも反映されて返ってくる
という状態になるので、初めての人でもそんなに違和感無く出来るのでは?と思う。
少なくとも僕はやりやすくなったんだけど。
非常に負荷のかかるやり方をしてしまってはいるとは思うんだけど、その分頭の中はすっきり整理出来るし、今のところはこれで良いのかなと思ってる。
このやり方で何度かテストを行ってるけど、そんなに大きな問題もないし。
まあ、全部のテストを一気にやると、なかなかレスポンスが返ってこなくなっちゃうってことぐらいかな。
この例は特に参考にするもの無く、自分でこんな感じかな?と思って手探りでやった結果なので、正しいやり方じゃないかもしれないけど、あまりネット上にもEthnaでのsimpletestの実例自体が見ないし、特にAppManagerクラスのテストとなると見たことが無かったので晒してみた。
参考になれば是幸い。
コメント