CodeLab技術ブログ

プログラミング技術まとめ

CakePHP2のコントローラーをUnitテストでしてみたが…

今まで、コントローラーのテストでPHPUnitはあまり使ってこなかったのですが、ちょっと試してみようかといろいろやってみたが…
正直使い勝手悪すぎる。

ダメな点その1-公式のチュートリアルがダメ

はっきり言ってわかりにくい。
そして、なぜか結果をデバッグプリントしているだけでテストになってない。
PHPUnitとか分かっている人にはassertでチェックするんだよと分かるけどね。

ダメな点その2-セキュリティーコンポーネント

まず困るのがセキュリティーコンポーネント。
POSTデータを改ざんされないようにトークンが付くんだけど、POSTをテストメソッドで渡しているからつけようがない。
この件に関するまともな情報が全然ない。
両方デフォルトで入っているコンポーネントなんだから、公式にやり方書いておいてほしい。

で、いろいろ調べてモック機能を使えば、コンポーネントのパラメータにアクセスできるらしいことが分かった。
ということでこんな感じに書いておけばいいらしいのだが・・・

	public function setup(){
		parent::setUp();
		$this->controller = $this->generate("Users",['components'=>['Security']]);
		$this->controller->Security->expects($this->any())->method('validatePost')->will($this->returnValue(false));
		$this->controller->Security->expects($this->any())->method('csrfCheck')->will($this->returnValue(false));
	}

これで、確かにセキュリティーコンポーネントが無効化されるのでテストにはパスする。
ただし、1回目だけw
Authでのログインのテストでこんな感じで書いたとして

	public function testAuth() {
		$data = [
			'User'=>[
				'name'=>'admin',
				'password'=>'password'
			],
		];
		$result=$this->testAction('/admin/users/login',
			['data'=> $data, 'method' => 'post','return' => 'contents']
		);
		$this->assertContains(Router::url('/', true), $this->headers['Location']);
		//ログアウト
		$result=$this->testAction('/admin/users/logout',['method'=>'get']);
	}

これは通るけど、同じtestAuth()メソッド内でもう1回ログインさせようとすると、なぜかSecurityComponentが有効になっていてエラーになってしいました。
まぁ、テストメソッドを分ければ通ります。が。。。ログイン後の再ログインみたいなテストもあるだろうし、理由がわからないのは気持ちが悪い。

セキュリティコンポーネントを外せば大丈夫なんだけど、テストのためにコードをいじるのはちょっとダメなんじゃないかな?

ダメな点その3-デバッグプリントが使えない

最も困るのがこれ。
デバッグプリントが使えません。
まぁ、使えることは使えるんですよ。デフォルトではOFFになっています。
コンソールの場合は”–debug”を追加、Webの場合は”Enable Debug Output”のリンクをクリックすれば出るようになります。
確かに出ます。

ただし、テストが正常に終了した場合だけ。エラーの時は出ません。
いや、普通さ、異常の時にどうなっているのか出したいわけじゃないですか?意味ないでしょ…。

というわけで、すごく使い勝手が悪いです。
ライブラリレベルの単体テストでは結構使えるんだけど、どうもVeiwレベルだといろいろ問題が多いようです。

うーん。これはどうしたものかな。

追記
コントローラーテストにこんなメソッドを作って、testAction()の前でコントローラー名付きで毎回呼べばOKになりました。

	public function setController($controller_name){
		$this->controller = $this->generate("{$controller_name}",['components'=>['Security'=>['validatePost','csrfCheck'] ]]);
		$this->controller->Security->expects($this->any())->method('validatePost')->will($this->returnValue(false));
		$this->controller->Security->expects($this->any())->method('csrfCheck')->will($this->returnValue(false));
		
		$this->controller->Security->validatePost=false;
		$this->controller->Security->csrfCheck=false;
	}


コメントは受け付けていません。