CakePHPのsimpleTestでStubを使ってみる

スタブを使ってみた。やりたいことは半分できたが、いそいろ分からないところも多かった(後日できた)

やりたかったこと

ComponentsをスタブにしてControllerのテストをしたかった。
今回の例で言うと「はてなブックマーク数」を取得するコンポーネントをスタブ化し、テストのたびにはてなAPIにアクセスしないようにしたかった。

できたこと

テスト内のコントローラーのコンポーネントインスタンスを上書きしてコンポーネントのスタブ化ができた。

できなかったこと

testActionで呼ばれたときのコントローラーのコンポーネントのスタブ化のやりかたがわからなかった(追記 => できるようになりました

前準備

まずブログチュートリアルのPostsテーブルをつくりbake allした。
コンポーネントbookmark.phpをこんな感じで作り

<?php
class BookmarkComponent extends Object {
	function num($url) {
	return file_get_contents("http://api.b.st-hatena.com/entry.count?url=".$url);
  }
}
?>

コントローラーで利用するようにした

<?php
class PostsController extends AppController {

	var $name = 'Posts';
	var $components = array('Bookmark');

	function index() {
		$this->Post->recursive = 0;
		$this->set('posts', $this->paginate());
		$this->set('bookmark', $this->Bookmark->num("http://www.yahoo.co.jp"));
	}
}
?>

これではテストのたびにはてなにアクセスしてしまうので、このコンポーネントをスタブ化したい。

やったこと

こんな感じにindexのテストを書き換えた

<?php
/* Posts Test cases generated on: 2010-07-13 20:07:58 : 1279019398*/
App::import('Controller', 'Posts');

class TestPostsController extends PostsController {
	var $autoRender = false;

	function redirect($url, $status = null, $exit = true) {
		$this->redirectUrl = $url;
	}
}

class PostsControllerTestCase extends CakeTestCase {
	var $fixtures = array('app.post');

	function startTest() {
		$this->Posts =& new TestPostsController();
		$this->Posts->constructClasses();
	}

	function endTest() {
		unset($this->Posts);
		ClassRegistry::flush();
	}

	function testIndex() {
		Stub::generate('BookmarkComponent');
		$this->Posts->Bookmark = new MockBookmarkComponent();
		$this->Posts->Bookmark->setReturnValue('num', 42);
    
		$this->assertEqual($this->Posts->Bookmark->num(''),42,"ブックマーク数は42である");
	}
}
?>

これでBookmarkのnumメソッドが上書きされ、常に42を返すようになった。