CodeIgniter1.7.2でSimpleTestを動かせました!

phpフレームワーク勉強会で作っているショッピングカートなのですが、
機能追加していくうちに、あるモデルクラスが大きくなってきたので、2つに分けようと考えています。


分割してコードが整理できるのはいいのですが、その結果、バグが生まれてしまっては本末転倒なので、
良い機会なので、ちゃんとテストを書こうと思い立ちました。


CodeIgniterには、ユニットテストクラスがあるのですが、いろいろ工夫しないと、
テストしたいコードの中に直書きになってしまうので、
PHPUnitとか、SimpleTestを使ってみたかったのですが、簡単にCodeIgniterに組み込めません。。。


始めは、CIUnit(PHPUnitをCodeIgniterで使えるようにするライブラリ http://www.knollet.com/foostack/)
CodeIgniter1.7.2に対応していることで使おうとしていたのですが、どうもうまく動かず...


http://groups.google.co.jp/group/php-beginner/web/ciunit に途中までの記録を残してあります。


そこで、SimpleTestを動かそうと


SimpleTester(http://codeigniter.com/wiki/SimpleTester_-_Unit_testing_library/)


を使おうとしてみたのですが、これもうまくいかず...画面真っ白


最終的に、CodeIgniter Wiki


http://codeigniter.com/forums/viewthread/63602/


に書いてある方法がうまくいったので備忘録として書いておきます。

1. test用ディレクトリの作成


system/application/


以下にtestというディレクトリを作ります。

2. SimpleTest(http://www.simpletest.org/)とCodeIgniterをつなぐヘルパーを作る


system/application/test/


の下に、


test_helper.php


という名前で作ります。
SimpleTestはダウンロードして、phpのinclude_pathの通っているところに配置して下さい。

<?php

require_once 'simpletest/unit_tester.php';
require_once 'simpletest/reporter.php';

class TestHelper extends UnitTestCase
{
  protected $CI;
  
  public function setUp()
  {
    $this->CI =& get_instance();
  }
} 

3. コントローラクラスを継承したクラスを作る


system/application/controllers/


の下に、intranet.php


という名前で作ります。

<?php

class Intranet extends Controller {

    public function Intranet()
    {
        parent::Controller();
    }
} 

4. testコントローラを作ります


system/application/controllers/


の下に、


test.php


という名前で作ります。

<?php

require_once 'intranet.php';

class Test extends Intranet {
  
  protected $sTestDirectory;
  protected $oTestSuite;

	function Test()
	{
		parent::Intranet();
		$this->sTestDirectory = dirname(__FILE__).'/../test/';
		require_once $this->sTestDirectory . 'test_helper.php';
		$this->oTestSuite = new TestSuite();
	}
	
	function index()
	{
		// 全テスト実行
		$this->all_tests();
	}

	function all_tests()
	{
		// テストコード
		$this->oTestSuite->addTestFile($this->sTestDirectory . 'models/shop_model.php');
		// テスト実行
		$this->run();
	}

	protected function run()
	{
	  $this->oTestSuite->run(new HtmlReporter());
	}
}

このIntranetクラスがあることで、TestクラスがCodeIgniterの決まり
(Controllerクラスを継承して、http://domain_name/index.php/コントローラ名でアクセスする)
を守りつつ、SimpleTestのクラスもロードできるようにする仕組みを提供しているという感じでしょうか(?)

5. テストコードを書く


/system/application/test/


の下に、


models


というディレクトリを作り、その下に、


shop_modelTest.php


という名前でテストコードを作ります。ここでの名前は慣例的に


テストしたいクラス + Test


としていますが、何でもいいみたいです。


system/application/models/shop_model.php


のテストをしてみます。


詳細は省略してますが、shop_model.phpは、このような内容だとします。

<?php
class Shop_model extends Model
{
        function Shop_model()
        {
                parent::Model();
        }

        function get_item_list()
        {
                return 100;
        }
}


shop_modelTest.phpは、

<?php
class Shop_ModelTest extends TestHelper
{
	public function setUp()
	{
		parent::setUp();
		$this->CI->load->model('Shop_model', 'remote');
	}

	// Shop_modelクラスにあるget_item_list()メソッドのテスト
	public function test_get_item_list()
	{
		// 結果を取得
		$aResult = $this->CI->remote->get_item_list();
		// 結果は100のはず...
		$this->assertEqual(100, $aResult);
	}

	// 以下、どんどんテストを書きます!
} 

のように書いておきます。


ここまでできたら、


http://CodeIgniterが動いているドメイン名/test


とアクセスしてみます。


なお、index.phpURIから消していない場合は、


http://CodeIgniterが動いているドメイン名/index.php/test


のようにアクセスします。


すると、

のような画面が出て、テストがうまくいっていることが分かります!
ちなみに、

<?php
	public function test_get_item_list()
	{
		// 結果を取得
		$aResult = $this->CI->remote->get_item_list();
		// 結果は100のはずだけど、わざと失敗させてみる
		$this->assertEqual(10, $aResult);
	}

とすると、


のような画面が出て、ちゃんと(?)テストが失敗することが確認できます。


ということで、ひとまず導入はできたので、これからテストをばりばり書いて行きたいと思います!!