2012-07-31

JICA WORLD REPORTER #7

JICAワールドレポーター更新。
多事多端


最近、ホントに活動(仕事?)が忙しい...そんなでこのブログも投稿が滞りがち。週末の予定は全てキャンセル、平日も毎晩2時くらいまで家で仕事をしてる。ここ2ヶ月間で出かけたのは平日の夜に外食に3回行っただけという引きこもり具合。万国共通でこの業界(IT系)は納期前になるとどうしてもこうなってしまうのか、自分のやり方が悪いのか、何だか日本で仕事をしていたときのようになってきた。

とはいえ配属先から納期や残業をとやかく言われているわけではなく、今まで自分で決めた納期を守れずズルズルと延長してきた自分に嫌気がさし、覚悟を決めてやってるわけなのだが...それにしてもやらなきゃならないことが多過ぎる。こんなに働いてるJICAボランティアは世界中探しても他に居ないんじゃないかなと思う。

こんな状況が9月末までは続きそう(というか、その頃までには終わらせたい...)。

開発環境のご紹介

朝9時に出社して昼休みに家に戻って1時間弱仮眠して、また職場に戻って6時頃に帰宅。その後は夕飯を食べてから2時くらいまで仕事をしてシャワー浴びて寝る。仕事中は独り黙々とコーディングしているだけ。そんな毎日の繰り返しなのでブログネタがないというのが正直なところ。というわけで、今回は同職種(同業者)向けに開発環境のご紹介。何という内輪ネタ(苦笑)。

開発概要:
ドミニカ国の保健情報を統合管理するWebサイトの構築

  • サーバー: Ubuntu 12.0.4 LTS
  • Webサーバー: Apache 2.2
  • DB: MySQL 5.5
  • 言語: PHP 5.3, Twig, Ajax(jQuery)
  • フレームワーク: Symfony2
  • 主要追加バンドル: StofDoctrineExtensionsBundle, DoctrineFixturesBundle, JMSSecurityBundle, KnpPaginatorBundle
  • ツール, モジュール: Google Maps API, FPDF, Spreadsheet_Excel_Writer
  • テストフレームワーク: PHP Unit, Stagehand_TestRunner
  • ソース管理: Git, git-flow, GitHub

こうして見るだけでも色んな知識が必要なのが分かる。しかも日本で仕事してた時よりはるかに最新の開発環境。ちなみに要求定義~設計~コーディング~テストまで全て独りです。根っからのソフト開発屋なのでWebの画面デザインとかあまり得意じゃないんだけどな...

2012-07-02

NetBeans で PHPUnit を使う際の注意

NetBeans 上で PHPUnit が使えるのは非常に便利だが、その際にNamespace を用いているクラスの場合、名前解決に結構クセがありハマったのでメモ。
以下いくつか注意点を列挙。

PHPUnitフレームワーククラス自体の名前解決

当然ながらテストクラスはnamespace宣言により、テスト対象クラスの名前空間になっているので、継承時にPHPUnit_Framework_TestCaseだけではダメで最初に"\" が必要。サイトや書籍のサンプルを試すときは要注意(テストクラス自動生成時は既に追加されている)。
namespace Hoge\Moge;
class SomeClassTest extends \PHPUnit_Framework_TestCase 
{
}

クラス読み込み(require_once)

テストで使用するクラスはモックを使用する場合でも全て読み込みをする必要がある。 通常テスト対象クラスとテストクラスはディレクトリが異なるので(例えばsrcとtestsのように)、そこまでのパスを相対指定する。
namespace Hoge\Moge;
require_once __DIR__ . '/../../../src/Hoge/Fuga/AnotherClass.php';

ただし、この方法だと階層が深いと読みづらい上に、使用クラスが多くなると大変。bootstrap.phpを用意してauto_loadを実装したクラスローダークラス等を先に読み込ませた方がスマート。
その場合は、プロジェクトのプロパティ>PHPUnitカテゴリーのUse Bootstrapにチェックしてファイルを指定するか、require_onceで読み込ませる。
namespace Hoge\Moge;
require_once __DIR__ . '/../../bootstrap.php';

この方法だと使用クラスが増えた際も、その都度個別のファイルを指定する必要がなく便利。

クラスインスタンス生成

通常のクラスインスタンス生成はuseキーワードを追加することで、ショート名を用いることができる。
namespace Hoge\Moge;
require_once __DIR__ . '/../../bootstrap.php';

use Hoge\Fuga\AnotherClass;

class SomeClassTest extends \PHPUnit_Framework_TestCase
{
    public function testMethod() {
        $class = new AnotherClass();
    }
}

モック生成時のクラス名指定

問題はモックを使用する場合で、requireで個別にファイルを読み込ませたか、クラスローダーに読み込ませたかに関わらず完全修飾名で指定する必要がある。
namespace Hoge\Moge;
require_once __DIR__ . '/../../bootstrap.php';

use Hoge\Fuga\AnotherClass;

class SomeClassTest extends \PHPUnit_Framework_TestCase
{
    public function testMethodNotUseMock() {
        $class = new AnotherClass();
        $this->assertEquals('foo', $class->doSomething());
    } 

    public function testMethodUseMock() {
        $stub = $this->getMock('Hoge\Fuga\AnotherClass');

        $stub->expects($this->any())
               ->method('doSomething')
               ->will($this->returnValue('foo');

        $this->assertEquals('foo', $stub->doSomething());
    }
}

なぜか、PHPUnitに渡すクラス名の場合、名前解決は完全修飾名ではないとダメな模様。自分は、これに引っ掛かって相当時間を費やした。もしかしたら設定で指定できるのかもしれないが、とりあえずこれでも解決。

Abstract クラス
抽象クラスのモックインスタンス生成はgetMockForAbstractClassを使う(抽象クラスはそもそもgetMockではインスタンス生成できない)。その際、具象メソッドはメソッド上書きの対象にならないので注意。抽象クラス上の具象メソッドを偽装させたい時は一度その抽象クラスを継承したクラスを宣言した上で、そのクラスをgetMockで上書きする必要がある。
// AbstractClass.php
abstract class AbstractClass
{
    public function notOverridable() {
        return 'hoge';
    }

    public function concrete() {
        $this->overridable();
    }
     public abstract function overridable();
}

-------------------------
// AbstractClassTest.php
class ConcreteClass extends Abstracrt
{
    public function overridable() {
        return 'fuga';
    }
}

class AbstractedClassTest
{
    public function testAbstractMethod() {
        $stub = $this->getMockForAbstractClass('AbstractClass');
        $stub->expects($this->array())
             ->method('overridable')
             ->will($this->returnValue('moge');

        // abstractメソッド(overridable()) は上書き(実装)される
        $this->assertEquals('moge', $stub->concrete());
    }

    public function testConcreteMethod() {
        $stub = $this->getMockForAbstractClass('AbstractClass');
        $stub->expects($this->array())
             ->method('notOverridable')
             ->will($this->returnValue('moge');

        // 具象関数 notOverridable は上書きされず 'hoge'が返される(アサート発生)
        $this->assertEquals('moge', $stub->notOverridable());
    }

    public function testOverridedConcreteMethod() {
        $stub = $this->getMock('ConcreteClass');
        $stub->expects($this->array())
             ->method('notOverridable')
             ->will($this->returnValue('moge');

         // ようやく overridable()  は上書き(実装)される
         $this->assertEquals('moge', $stub->notOverridable());
     }
}

もっともこのように抽象クラスの具象メソッドを偽装させたい時に、テストクラス側に抽象クラスのサブクラスを記述しなければならないのであれば、あまりgetMock系メソッドの恩恵は少ないように感じなくもないが、それでもなお各テストメソッドにおいて動的に返り値を指定できるというメリットは大きい。
 
Copyright 2010 toconuts. Powered by Blogger Blogger Templates create by Deluxe Templates. WP by Masterplan