ひよっこ。

I want to…

Posts Tagged ‘Flex’

fxug@北陸in富山をやったよ。

Posted by hikaruworld : 2011 4月 24

ずいぶん間が空いてしまいましたが、
fxug@北陸in富山をやりました。

スピーカーしてくれたwacky,@itsuki_kosen,@shoito
参加してくれた皆さん、ありがとうございます。
次は6月に金沢ですので興味ある方は是非〜。

個人的には富山で初見の人に会えたのがうれしかった!

久々に話しましたが、相変わらずぐだぐだに。
もっと練習しないとなー。

という訳で、セッション内容を張っておきます。
今回はMockitoというFlexのモッキングフレームワークについて話しています。

広告

Posted in program | タグ: , , , , | Leave a Comment »

Mockito-Flexを利用してFlexのTDD/BDD環境を構築する(その2)

Posted by hikaruworld : 2011 2月 16

前回の続きになります。

Mockito-Flexの使い方

Java版のMockitoとの差異

基本的にはJava版のMockitoとほぼ同じですが、メソッドなど異なる部分もあります。
Java版のMockitoでは振る舞いのエミュレートの部分では、
when().thenを利用していましたが、mockito-flexの場合は、
given().willを利用する事になります。BDDMockito側を実装しているようですね。

ちょっとつらいのは、現在のmockitoでは複数の振る舞いの定義が出来ていないため、
以下のようなmockを書いても

given(hoge.piyo()).willReturn(“a”);
given(hoge.piyo()).willReturn(“b”);
given(hoge.piyo()).willReturn(“c”);

実行すると、以下のようになってしまいます。

trace(hoge.piyo()) // “a”
trace(hoge.piyo()) // “a”
trace(hoge.piyo()) // “a”

これは、Mockit-flex側でもIssuesとして、
#17 Multiple called given(something).willReturn(something) always returns first setted value
があがっていますが、まだ対応がはいっていないようです。
一応Answerを利用したやり方はあるようですので後述します。

Java版と同様な部分としては、DSL的な記述が可能なように
org.mockito.integrations以下にメソッド群が切り出されています。
Flex版ではグローバルメソッドとして定義されており、
Javaのようなstaticインポートが不要なところは言語的に楽ですね。

なお、これらのメソッドは実際はorg.mockito.Mockitoの
フィールドを呼び出すようになっています。
実際の挙動を確認する場合は、Mockitoの中身を確認すると良いかと思います。

Mockitoによる実装

ここからmockitoによって提供されている機能を確認していきます。
その際テスト対象のクラスが必要になりますので、
以下のクラスを対象にテストを行います。

public class Main
{
    public function Main()
    {
    }
    public function say(name:String):String
    {
        return "Hi " + name;
    }
    public function say(name:String):String
    {
        return "Hi " + name;
    }
    public function sayObj(obj:Object):String
    {
        return "obj is " + name;
    }
    public function check(data:Data):String
    {
        return data.userId;
    }
}
public class Data
{
	public var userId:int;
	public function Data()
	{
	}
}

なお、前回の方法でtargetに格納されている事とします。

Mock化

任意のクラスをMock化して振る舞いを設定する場合の方法です。

givenによる振る舞いの設定

given()を利用する場合は、以下のように記述します。

given(mock化するメソッドとその引数).willReturn(戻り値)

givenの引数にはmock化するメソッド[Mock]対象と、エミュレートしたい引数を設定します。
この引数はmockitoが提供するメソッドを利用して柔軟に設定する事が可能です。
willReturnはgivenによって与えられた条件時に返す値を定義します。
willReturn以外にも、will,willThrowがあります(詳しくは後述)。

引数のmock化

given時に引数をmock化するためのメソッドを見ていきます。

any()

any()は引数にどんな値を与えられても良い事を表します
(当然引数で定義される型の範囲内でですが)。
なお、any()はnull値を許容しますので、値がnullの場合でもmockとして処理されます

/**
 * anyのテストケースを検証_NULLでない場合
 */
[Test]
public function any_is_not_null():void
{
	given(target.say(any())).willReturn("piyo");
	
	var result:String = target.say("abc");
	
	assertThat(result, isA("piyo"));
}
/**
 * anyのテストケースを検証_NULLの場合
 */
[Test]
public function any_is_null():void
{
	given(target.say(any())).willReturn("piyo");

	// nullの場合でもwillReturnの値が返される
	// ちなみにundefでも問題なし
	var result:String = target.say(null);
	
	assertThat(result, isA("piyo"));
}

anyOf(Class)

anyOfも引数にどんな値を与えられても良い事を表します。
anyOfの引数には、対象の型を指定します。
例えばStringの場合は、anyOf(String)のように引数の型を指定します。

/**
 * anyOfのテストケースを検証_NULLでない場合
 */
[Test]
public function anyOf_is_not_null():void
{
	given(target.say(anyOf(String))).willReturn("piyo");

	var result:String = target.say("abc");

	assertThat(result, isA("piyo"));
}

ただし、前述のany()と異なりnull値を許容しません。mock化したメソッドに対して、
nullを引数に呼ばれた場合はArgumentErrorがthrowされます。

ArgumentError: obj cannot be null

havingPropertyOf

havingPropertyOf(property, value)は引数の持つプロパティの値が一致する場合に、
実行することが可能です。

[Test]
public function havingPropertyOf_test():void
{
        // 引数に渡されたプロパティuserIdが12の場合だけmock処理を行うように設定
	given(target.check(havingPropertyOf("userId", 12))).willReturn(22);

	var data:Data = new Data();
	data.userId = 12;
        // この場合にはwillReturnで指定した22が結果としてかえる。
	var result:int = target.check(data);

	verify().that(target.check(data));
	assertThat(result, isA(22));
}

TODO 継承周りとか調査

isItNaN

これはNaNつまり非数である場合にのみMock処理を行うために利用されます

[Test]
public function isItNaN_test():void
{
	given(target.sayObj(isItNaN())).willReturn("NaN value");

	var result:String = target.sayObj(Number.NaN);

	assertThat(result, isA("NaN value"));
}

notNull

そのまんまですね。値がnullでない場合のみMockのエミュレーションが実行されます。

[Test]
public function notNull_test():void
{
	given(target.say(notNull())).willReturn("Value is Null");

	var result:String = target.say("hoge");

	assertThat(result, isA("Value is Null"));
}

と、今回はこの辺で。
次回はverify周りに付いて書きます。

Posted in program | タグ: , , , , | Leave a Comment »

Mockito-Flexを利用してFlexのTDD/BDD環境を構築する(その1)

Posted by hikaruworld : 2011 2月 14

FlexでもユニットテストやMockライブラリが充実し、ずいぶんテストがしやすくなっています。
そこで、FlexでTDD/BDD環境の構築をしてみます。
なお、環境は以下のように構築しています

IDE FlashBuilderBurittoPreview
TestingFramework FlexUnit4 / Hamcrest-as / Mockito-Flex

Mockito-FlexはMock処理を簡単に行うためのフレームワークです。
内部的な実装はASMockに依存していますが、Mockitoを利用することで
ASMockのRecord->Replayの処理を省いて簡単にMockが作れるようになります(なるはず…)。

ライブラリの入手

必要な物を一通りダウンロードしてlibs以下においてパスを通します。

mockito-flex

今回の話題となるMockito-Flexです。
ここから現在の最新版1.4M5をダウンロードします。

FlexUnit4

FlashBuilder4にもFlexUnit4は同梱されているのですが、
ちょっと古いらしくRuleの実装がはいっていないバージョンです。
mockito-flexを利用する際、[Rule]があると楽できるため、ここから最新を落としておきます。
ちなみにバージョンは、FlexUnit4.1RC2でした。

Hamcrest-AS3

どうせなのでHamcrestのバージョンも最新にしておきましょう。
Hamcrest-as3はgitHubのここにあります。現時点での最新のバージョンは1.1.3になります。

テストうんぬん前にまずやるべき事

mockitoは最新版はAPIドキュメントなどもないので、ソースをダウンロードしておきます。
ソースはswcに紐つけておきましょう。
(Referenced Libraries -> mockito.XXX.swc -> 右クリックしてプロパティ -> ソース添付 -> 編集)
あと忘れずに、ASDocを作っておきます(以下はコマンドラインから)。

$ pwd
mockito-flex/mockito/src
$ asdoc -source-path ./main/flex/ -doc-sources ./main/flex/ -library-path ../libs/

まだドキュメントが十分そろっていないようですし、分からなくなったらASDocとソースを見るのが解決に一番の近道です。

テストのやりかた

さて、本題です。
ここにmockitoをFlexUnit4で動かすやり方が書いてありますので手順に従ってやっていきます。

基本的なやり方

mockitoをFlexUnit4上で利用するには3つの方法があるようです。

方法1:従来のケース

従来の方法?では、テストクラスへの[RunWith]を利用してmock化を行います。

/**
 * クラス宣言時にFlexUnit4の[RunWith]を利用してMockitoClassRunnerを指定
 */
[RunWith("org.mockito.integrations.flexunit4.MockitoClassRunner")]
public class MainTest
{
  /** Mock化対象のクラスを定義 */
  [Mock(type="com.wordpress.prepro.Main")]
  public var target:Main;
  
  // Testコード...
}

方法2:新しい方法(インスタンス化の制御を自信で行わない)

この方法を利用した場合、[Rule]の機能を利用してMockのインスタンス化が制御されます。
そのため、MockitoRuleを[Rule]メタタグを付けて初期化しておく必要があります。
ただし、インスタンス化の制御を[Rule]に依存するため、RunWithの設定を必要としません。

なお前述しましたが、Ruleは現在FBに同梱されているFlexUnitには含まれていません
ライブラリの部分の手順に従って、事前に最新版に置き換えておく必要があります。

/** [RunWith]は不要 */
public class MainTest
{
  /**
   * [Rule]でMockitoRuleをインスタンス化
   */
  [Rule]
  public var mockitoRule:IMethodRule = new MockitoRule();

  /**
   * Mock化対象クラスの宣言
   * 必ず***public***である必要がある。
   */
  [Mock(type="com.wordpress.prepro.Main")]
  public var mockie:Main;
  
  // Testコード...
}

なお、Mock化したいクラスにコンストラクタ引数が存在する場合は、以下のように設定します。
こうする事で、Mainクラスに引数1がコンストラクタ引数として渡されます。

/**
 * typeでMock化したいクラスを指定
 * argsListでコンストラクタに渡す値をもつフィールドを指定します
 */
[Mock(type="com.wordpress.prepro.Main", argsList="args")]
public var target:Main;
/**
 * Mock化するクラスに渡す引数を配列形式で定義します。
 */
public var args:Array = [1];

※ただし、この方法はドキュメント上には見つかりませんでした。
テストコードで見つけたので、今後どうなるかは不明です。

方法3:新しい方法2(インスタンス化の制御を自力で制御する)

方法2ではテスト実行時にmockオブジェクトが初期化※0されますが、
この方法を用いるとmock()メソッドを利用してmockオブジェクトのインスタンス化を制御します。

/**
 * Mock化対象クラスの宣言
 */
[Mock(type="com.wordpress.prepro.Main")]
public class MainTest
{
  /**
   * [Rule]でMockitoRuleをインスタンス化
   */
  [Rule]
  public var mockitoRule:IMethodRule = new MockitoRule();

  public var target:Main;
  
  // テストコード
  [Test]
  public function test():void
  {
    // mock()でmock化
    this.target = mock(Main);
  }
}

この方法のメリットは好きなときにmock化を制御できること、
また、その際にコンストラクタ引数を任意に指定できる事だと思います。

/**
 * Constructs mock object
 * @param clazz a class of the mock object
 * @param name a name used in various output
 * @param constructorArgs constructor arguments required to create mock instance
 * @return a mocked object
 */
function mock(clazz:Class, name:String=null, constructorArgs:Array=null):*;

とあるように、第一引数にMock化したいクラス名、第二引数にエイリアス?、
第三引数にコンストラクタ引数を指定する事が出来ます。

方法2のフィールド指定によるMock化では、コンストラクタ引数をプロパティとして、
定義しておく必要がありますが、方法3では、テストメソッド内でMockを組み立てながら、
引数を考える事が出来ます。

なお、不適切な引数の状態でMock化を指定した場合、
初期化時に以下のエラーが発生してしまいます。

ArgumentError: Incorrect number of constructor arguments supplied.

※0具体的には[Test]の実行時単位で初期化されます。

設定を間違った場合(タイポや、privateフィールドにしていたetc)などはmockオブジェクトの初期化に失敗するため、
nullアクセスのエラーが以下のようにメッセージ出力されます。
今のFlashBuilderだとカスタムメタデータまでは補完してくれないので、タイポに気をつけましょう….

TypeError: Error #1009: Cannot access a property or method of a null object reference.

何だか長くなってしまったので次に続きます。
次は、実際にmockやverifyを利用して[Test]を実行していきます。

Posted in program | タグ: , , , , | Leave a Comment »

Flashのアクセシビリティに関する特集

Posted by hikaruworld : 2010 3月 27

表題に関して技評で特集をやっていますね。
http://gihyo.jp/design/serial/01/flash_accessibility/0001

個人的には、とてもタイムリーな話題です。
先日fxug@富山での発表用の資料を作ってる時に自分も色々調べていたのですが、
日本語の資料が少なくてびっくりしました。

英語の方では、Flashのアクセシビリティにおけるベストプラクティクスが
定義されていたりはするのですが。

思っている以上に、Flash(Flex)におけるアクセシビリティサポートは、
限定的なものが大きいのが現状です(Win限定、IE上のActiveXプラグインOnlyなど…)。

ただ、Flex3ではなんとアクセシビリティ機能がデフォルトFalseだったFlexですが、
Flex4からはアクセシビリティ機能がデフォルトTrue(有効)になっています。
このあたりの対応を今後本格的に行っていくのだろうと期待感があったりはします。

企業内アプリを作成していると、こういった部分はおろそかになりがちですが、
アクセシビリティ難民を作らないように心がけていきたいものです。

この連載は楽しみです。

以上。

Posted in program | タグ: , , | Leave a Comment »

GeohashのAS3版

Posted by hikaruworld : 2010 2月 10

を適当に作ってみました。

Geohashとは何かに関しては、Wikipedia(英語)のGeohashが参考になるかと思います。
簡単にいうと緯度経度情報の矩形情報を特定の文字列を使って表現することができる仕様です。

アルゴリズムの日本語の解説としては

の記事がわかりやすいと思います。

自分の文系脳みそでも理解できました。ありがとうございます。

一応簡単にテストは済ませてありますが、勢いで作ったのであんまり自身なし。
浮動小数演算そのままやっているので丸め誤差が出ると思います。
launchpad.netのここからダウンロードできます。

bit演算とかした方が良いのかもしれませんが、恥ずかしながら普通にやってしまいました。
勉強し直してから修正します。

以下の機能が実装してあります。

  • エンコード機能(緯度/経度情報をgeohashに変換する)
  • デコード情報(geohash情報を緯度/経度に変換する)

以下はTODO

  • キャッシュの実装
  • 矩形の上下左右9方向への移動
  • 拡大/縮小機能
  • 隣り合うgeohashの取得方法
  • googleのジオコーディング連携

使いかたはGeoSampleを見ても分かりますが、以下の通りです。

// インスタンス化
var geo:Geohash = new Geohash();

// 富山城址公園の緯度経度をgeohashにエンコード
var hash:String = geo.encode(36.693286, 137.210877);
trace(hash);

// 富山城址公園のgeohashを緯度経度にデコード
var latlng:Object = geo.decode("xn98drccvhm2");
// Objecetの"lat"と、"lng"でそれぞれの情報を取得可能
trace(latlng[Geohash.LAT_KEY], latlng[Geohash.LNG_KEY]);

バグがあれば指摘していただけると助かります。

以上です。

Posted in program | タグ: , , , | Leave a Comment »

Air2.0(ベータ版)でネイティブプロセスでjarファイルを実行する方法(泥臭い編)

Posted by hikaruworld : 2009 12月 13

Air2.0(現時点ではβ1版)での新機能の一つとして、ネイティブプロセスを実行することができるようになっています。

詳細はこのあたりが参考になります。

  1. AIR 2.0 ではじめるコミュニケーションツール Comm On AIR 2.0

この新機能を用いてjarファイルを実行したかったのですが、
ちょっと面倒な実装になってしまったのでメモしておきます。

ちなみに環境はMacOSX(雪豹)です。
winだとjarファイルを直接渡しても実行してくれるのかなぁ(javaw -jar hoge.jar)。

結論としては、jarファイル単体実行が結局うまくいかずshのラッパーを用意しました。

  • bin/exec.jar
  • bin/wrapper.sh

という感じでアプリケーションに実行ファイルを含めておきます。

exec.jarはマニュフェストファイルが存在する実行可能jarファイルで固めてあります。
wrapper.shの中身はこんな感じです。

#!/bin/sh

# 単純にjava -jarで第一引数に実行対象のjarファイルを渡す。
# jarファイルにパスが通っている前提
$(java -jar $1)

java -jarコマンドを実行時に$1でwrapper.shに渡された
引数(これが実行対象のjarファイルになります)をそのまま指定しています。

Air2.0側では、以下のような実装を書きました。

var info:NativeProcessStartupInfo = new NativeProcessStartupInfo();
// 実行対象のファイル(ラッパー)を指定
var file:File = File.applicationDirectory.resolvePath("bin/wrapper.sh");
info.executable = file;

// wrapper.shに渡す引数を指定
var args:Vector.<String> = new Vector.<String>();
// 相対指定だとAirのランタイムからの指定になってしまうので、
// 実際にjava -jarコマンドに渡したいファイルの絶対パスを解決する。
var jarFile:File = File.applicationDirectory.resolvePath("bin/exec.jar");
args.push(jarFile.nativePath);
info.arguments = args;

// 実行
this.process = new NativeProcess();
process.start(info);

ソースコード上のコメントにもありますが、
ネイティブプロセスによって実行されたファイルのカレントディレクトリ(pwd)が、
AirのRuntimeになってしまうようで、アプリ内に存在するファイルの
絶対パスを解決して渡しているとう微妙な実装をしています。

以上。

めちゃめちゃ泥臭い実装なんですが、
よりより方法があれば誰か教えてください。

Posted in program | タグ: , , , | 1 Comment »

Flash制作に欠かせない3つのツール・FlexBuilderプラグイン編

Posted by hikaruworld : 2009 10月 14

なんだか、そここらで標題をやっているので自分も乗ってみます。
ちなみに自分はちょっと視点を変えて、FlexBuilderPluginの観点から。

  1. TODO/FIXME プラグイン
    タスクはEclipseデフォルトビューの一つで、Javaなどの場合は問題なく表示されるのですが、Flexはそれを拾ってくれません。
    このプラグインはFlexのMXML及びAS上のTODOとFIXMEを認識してタスクタブ上に表示してくれます。
    FlexBuilder2用なのですが、FlexBuilder3でもFlashBuilder4 Beta2でも動きます。
    自分は「とりあえずTODO」が多いので非常に助かります。

  2. Blueprint プラグイン
    選択したクラスやメソッドのヘルプとサンプルソースコードを開いてくれます。
    大変便利なのですが、開かれるASDocが英語というのがタマに傷。
    日本語に出来るともっといいのですが。

    FlashBuilder4 Beta2では動かないのは私だけですかね。

  3. FlexFormatter プラグイン
    記述されたコードのフォーマットをしてくれるプラグイン。
    適当なインデントで書いたコードも、さっくりインデントなどの
    フォーマットをしてくれる優れものです。

個人的には、CheckStyle的なプラグインがのどから手が出るくらい欲しいのですが、
他人任せに祈っていたりします。

以上ー。

Posted in program | タグ: , , | 2 Comments »

FlexPMDのRC4が出ていた

Posted by hikaruworld : 2009 9月 25

以前の投稿で、Hudson上にFlexPMDの環境構築を行いました。
その際に、以下のようなバグがあって正常にGUIで参照できませんでした。

本来はこれで問題なく参照できるはずですが、sourceが表示されず対応行がビジュアルに表示されませんでした。
Violationの設定がおかしかったのかなとも思ったのですが、filenameが絶対パスで示されている関係なのかなぁと思ったりして検索してみたら、こんなのを見つけました。
http://forums.adobe.com/message/2242523#2242523
http://bugs.adobe.com/jira/browse/FLEXPMD-70

いつ修正されるかなーと思いstarをつけて経過を見ていたんですが、
今回リリースされたRC4で修正されたと聞いて早速試してみました(修正一覧はこちら)。
すると無事修正されてソースコード上で参照できるようになっていました。
中の人ありがとーございます。

#TODO 今手元に反映版がないので後で反映版を貼付けること

Posted in program | タグ: , , | Leave a Comment »

FlexのCI用のビルド環境を構築する。

Posted by hikaruworld : 2009 9月 20

先日FlexPMDが出たと話題になっていましたが、
これ幸いと思い、Hudsonと一緒にCI環境を構築する事にしました。

# 今回のエントリはメモ的要素が非常に大きいです。
# 会社に持っていってそのまま使いたかったので…

具体的には、基本的な項目のみで以下のように行っています。

  • コンパイル
  • ASDocの出力
  • FlexPMDの実行

なお、今回とりあえず放置したことも多々あります。

  • パブリッシュ(.air化)
  • 自動テストの実行(FlexMonkey & Flexcover & FlexUnit4)

以下は実際の手順になりますが、
今回試したのはAir環境なので必要に応じてFlexと読み替えてください(aasdocがasdocとか)。
また、基本的な方針として出来る限り1プロジェクト内にすべてのbuildファイルを含める方針でいきたいと思います。
ディレクトリ構成は以下の通り。

.
|-- report											APPLICATION_ROOT
    |-- AIR_readme.txt								FlashDevelopにより生成されたファイル
    |-- CreateCertificate.bat						FlashDevelopにより生成されたファイル(証明書付与用)
    |-- Report.as3proj								FlashDevelopにより生成されたファイル(FD用の設定ファイル)
    |-- PackageApplication.bat						FlashDevelopにより生成されたファイル(パッケージ化用)
    |-- SelfSigned.pfx								証明書ファイル
    |-- air											PackageApplication.batにより生成されるリリース用ディレクトリ
    |   `-- Report.air								パッッケージ化されたAirファイル
    |-- bin											swfファイルの保存場所(Antにより生成)
    |   `-- Report.swf								コンパイルされたswfファイル
    |-- bin-debug									デバック用ディレクトリ(FlexBuilder及びFlashDevelopにより生成)
    |-- build										hudson用の各種ビルドファイル
    |   |-- build-doc.xml							ASDocビルド用
    |   |-- build-pmd.xml							FlexPMD実行用
    |   |-- build.xml								コンパイル用
    |   |-- ruleset.xml								FlexPMD用のルールセット(今回は利用しない)
    |   `-- output									ビルドファイルの実行結果格納先
    |       |-- AppDocs								build-doc.xmlによって書き出されたASDoc
    |       `-- pmd.xml								FlexPMDの出力結果
    |-- libs
    |   `-- ext
    |       |-- flexpmd								FlexPMDで利用されるライブラリ。
    |       |   |-- LICENSE.txt
    |       |   |-- ant-1.7.0.jar
    |       |   |-- as3-parser-1.0.RC3.jar
    |       |   |-- as3-parser-api-1.0.RC3.jar
    |       |   |-- as3-plugin-utils-1.0.RC3.jar
    |       |   |-- commons-lang-2.4.jar
    |       |   |-- flex-pmd-ant-task-1.0.RC3.jar
    |       |   |-- flex-pmd-core-1.0.RC3.jar
    |       |   |-- flex-pmd-files-1.0.RC3.jar
    |       |   |-- flex-pmd-ruleset-1.0.RC3.jar
    |       |   |-- flex-pmd-ruleset-api-1.0.RC3.jar
    |       |   |-- plexus-utils-1.0.2.jar
    |       |   `-- pmd-4.2.2.jar
    |       `-- flexunit4							FlexUnit4関連のライブラリ(今回は利用しない)
    |-- obj											FlashDevelopにより生成される
    |-- src											ソースディレクトリ
    |   |-- Report-app.xml						設定ファイル
    |   |-- Report.mxml							メインクラス
    |   `-- com
    |       `-- wordpress
    |           `-- prepro
    `-- test										テストディレクトリ
        |-- com
            `-- wordpress
                `-- prepro
OS CentOS5.3 VMWareの仮想アピアランスを利用
SCM Subversion1.4.2 yumにてインストール
CI hudson1.3.23 ViolationsPluginをインストール済み。
Ant 1.7 Hudson上の自動インストールを用いてインストール
FlexSDK 3.3.0.4852 /usr/local/flexはシンボリックリンクで定義しており、実体は/usr/local/flex3.3/

0. Subversion & Hudson & Ant & FlexSDKのインストール

省略。SubversionとHudsonは同一PC上にあるものとします。
SubversionはApache上で動かし、Hudsonはとりあえずjava -jar hudson.warで起動します。
また、Antに関しても、Hudsonの自動インストールを利用するものとします。

なお、FlexSDKに関しては/usr/local/flex以下にFlex3.3系の最新版を/usr/local/flexにインストールします。

1. コンパイル

FlexSDK3.3系ではFlexAntは既にSDkに内部に含まれていますのでFlexSDKをインストールしていれば不要です。
mxmlcをもちいてswfファイルを出力しているのは、後にFlexcoverやFlexmonkeyで読み込ませてテストを行う場合に必要になることを考えての事です(今回は意味ない..)。

<?xml version="1.0" encoding="UTF-8"?>
<project name="flexAnt" default="main" basedir="./">
	<description>
		FlexAntを用いてAirのコンパイルを行います
	</description>

	<!-- Hudsonの提供する環境変数を設定(実際にはこのbuild.xmlでは使われない) -->
	<property environment="env" />

	<!-- 各種プロパティ定義 -->
	<!-- FlexSDKのホーム -->
	<property name="FLEX_HOME" value="/usr/local/flex"/>
	<!-- アプリケーションのルート -->
	<property name="APP_ROOT" value="../"/>

	<!-- flex用Antタスクを読み込む -->
	<taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/ant/lib/flexTasks.jar"/>

	<!-- mxmlcの実行 -->
	<target name="main">
		<mxmlc file="${APP_ROOT}/src/Report.mxml" output="${APP_ROOT}/bin/Report.swf">
		<!-- mxmlc file="${APP_ROOT}/src/Report.mxml" keep-generated-actionscript="true" -->
			<!-- load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/ -->
			<load-config filename="${FLEX_HOME}/frameworks/air-config.xml"/>
			<source-path path-element="${FLEX_HOME}/frameworks"/>
		</mxmlc>
	</target>
</project>

2. ASDocの出力

ASDocを出力するためには、FlexSDK配下のbin/asdocを利用します。
が、FlexはasdocですがAirの場合aasdocを利用することになりますので注意してください。
また、ここでも指摘されていますが、linuxやmacでaasdocを利用する場合改行コードの
CRLFになっており正常に実行できませんので、改行コードを置き換える必要があります。

以下がasdocを出力するためのantになります。基本的にはここのテンプレート利用して任意に修正してください。

<?xml version="1.0" encoding="UTF-8"?>
<project name="asdoc" default="main" basedir=".">
	<description>
		AsDoc出力用のAntファイルです
	</description>
	
	<!-- Hudsonの提供する環境変数を設定(実際ここでは利用されない) -->
	<property environment="env" />

	<!-- 各種プロパティ定義 -->
	<!-- FlexSDKのホーム -->
	<property name="FLEX_HOME" value="/usr/local/flex"/>
	<!-- アプリケーションのルート -->
	<property name="APP_ROOT" value="../"/>
	<!-- aasdocへのパス -->
	<property name="ASDOC_EXE" location="${FLEX_HOME}/bin/aasdoc"/>
	<!-- ASDoc出力対象のソースディレクトリ -->
	<property name="AppClasses.dir" location="${APP_ROOT}/src/"/>
	<!-- ASDocの出力対象のディレクトリ -->
	<property name="Output.dir" location="${basedir}/output/AppDocs" />

	<!-- flex用Antタスクを読み込む -->
	<taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/ant/lib/flexTasks.jar"/>

	<!-- デフォルトの実行クラス -->
	<target name="main" depends="clean,compile" description="full build of asdocs"/>

	<!-- 既存のOutputを削除して新規作成するCleanUp -->
	<target name="clean">
		<delete dir="${Output.dir}" failOnError="false" includeEmptyDirs="true"/>
		<mkdir dir="${Output.dir}"/>
	</target>
	<!--
	 -	ASDocの実行。FlexAntタスクなどで定義されているわけではないので、execタスクを利用して直接aasdocを実行する。
	-->
	<target name="compile">
		<exec executable="${ASDOC_EXE}" failonerror="false">
			<arg line='-source-path ${AppClasses.dir} ${FLEX_HOME}/frameworks/'/>
			<arg line='-doc-sources ${AppClasses.dir}/com/wordpress/prepro'/>
			<arg line='-window-title "Report"'/>
			<arg line='-output ${Output.dir}'/>
		</exec>
	</target>
</project>

3. FlexPMDの実行

FlexPMDを実行するためには以下から必要な物をダウンロードする必要があります。
本来であれば外部にjarファイルをおいてそちらを参照すべきなのですが、
今回はプロジェクト内部に含める形にします(諸事情により)。
はまった点としてはチュートリアルにある方法では上手くいかなくて、classpathをはずしたら上手くいきました。
また、チュートリアルでは値を変数設定していますが、ここでは割り切って相対パスで指定しています。

<?xml version="1.0" encoding="UTF-8"?>
<project name="Flex PMD example" default="test" basedir=".">
    <description>
        taskdef flexPmdの定義テスト
    </description>

    <!--**************************************************** 
                FlexPMDを定義する
        *****************************************************-->
	<taskdef name="flexPmd" classname="com.adobe.ac.pmd.ant.FlexPmdAntTask" >
        <classpath>
            <pathelement location="../libs/ext/flexpmd/as3-parser-1.0.RC3.jar"/>
            <pathelement location="../libs/ext/flexpmd/as3-parser-api-1.0.RC3.jar"/>
            <pathelement location="../libs/ext/flexpmd/as3-plugin-utils-1.0.RC3.jar"/>
            <pathelement location="../libs/ext/flexpmd/commons-lang-2.4.jar"/>
            <pathelement location="../libs</classpath>/ext/flexpmd/flex-pmd-ant-task-1.0.RC3.jar"/>
            <pathelement location="../libs/ext/flexpmd/flex-pmd-core-1.0.RC3.jar"/>
            <pathelement location="../libs/ext/flexpmd/flex-pmd-files-1.0.RC3.jar"/>
            <pathelement location="../libs/ext/flexpmd/flex-pmd-ruleset-1.0.RC3.jar"/>
            <pathelement location="../libs/ext/flexpmd/flex-pmd-ruleset-api-1.0.RC3.jar"/>
            <pathelement location="../libs/ext/flexpmd/plexus-utils-1.0.2.jar"/>
            <pathelement location="../libs/ext/flexpmd/pmd-4.2.2.jar"/>
        </classpath>
    </taskdef>

	<target name="test">
        <flexPmd 
        	shortFilenames="false"
            sourceDirectory="../src" 
            outputDirectory="output/" />
	</target>
</project>

これでoutput以下に、pmd.xmlを出力しますので、hudson側でこんな感じに設定してやります。

HusonのViolations設定

HusonのViolations設定


すると、HudsonのView上で確認することが出来るようになります。
Violation結果

Violation結果

問題点

本来はこれで問題なく参照できるはずですが、sourceが表示されず対応行がビジュアルに表示されませんでした。
Violationの設定がおかしかったのかなとも思ったのですが、filenameが絶対パスで示されている関係なのかなぁと思ったりして検索してみたら、こんなのを見つけました。

RC4で対応されるみたいなので、また改めて試してみようと思います。

2009/09/20 追記

これを書いたのは9/8頃だったんですが(そのまま放置(汗))今日(9/20)に見たら、
know issureとしてFlexPMDのトップページに以下が表示されるようになっていました。
今後に期待ということで…

Stack traces can be thrown during parsing. They are caught though during analyzing the code base, and hence fails over

Posted in program | タグ: , , | Leave a Comment »

FlexAutomationAPIに関して

Posted by hikaruworld : 2009 9月 17

FlexAutomationAPIの説明がぐだぐだになったので、悔しいのでblogで補足していきます。

FlexAutomationAPIとは

FlexAutomationAPIとは、Flexフレームワークで提供されているAPIで
Flexコンポーネントに対するユーザ操作をオートメーションする事が可能になります(と、解釈しました)。

ただし、このAPIはFlexBuilderProfessionalが必須に成ります。
※standard版でも実行可能ですが、一回あたりのアクション数が30回に限定されています。
(リリースドキュメントに書いてあったんですが、探すに苦労しました…)

これは、FlexAutomationAPIを利用するのに必要なライブラリ

  • automation.swc — Flexコンポーネントの委譲クラス群
  • automation_dmv.swc — FlexチャーティングとAdavancedDataGrid用の委譲クラス群
  • automation_agent.swc — agentクラス

が通常のFlexSDKに含まれていないためです。

AutomationAPIで実現可能なこと

FlexAutomationAPIを用いると以下の事が実現可能だとヘルプには書いてあります。

  1. メトリック(Omniture) — Adobeが買収しましたが、要するに詳細なアクセス解析を提供します。
  2. 自動テスト(FlexMonkey & MerquryQTP) — 周知の通りユーザ操作をエミュレートしてGUIテストの自動化を行います。
  3. コブラウジング — 特にサンプルがあるわけではありませんが、リモートでのユーザ操作の同期などを可能とします。ここ辺り(PDF)が参考になるかと思います。

AutomationAPIのフロー

AutomationAPIはAutomationManagerの実行によって対象Flexコンポーネントを委譲する形で組み込まれます。
(正確にはAutomationManagerによってSystemManagerに対してADDEDイベントが登録され、
SystemManagerにADDされるタイミングで委譲クラスがインスタンス化され、
Automationの静的プロパティdelegateClassMapに追加されます。)

# AutomationManager自体はAPIドキュメントが存在せず、インターフェイスの
# IAutomationManager,IAutomationManager2のみしか参照できません
# このようにFlexAutomationAPI関連はAPIドキュメント上に表示されない@privateなものが多いようです。
# AutomationManagerは参照できませんがAutomationはソースが参照できますので直接のぞいてみるとよいでしょう。

この辺りはヘルプを参照して頂くと理解が進むと思います(以下の図を参照。Adobeのヘルプより)。

AutomationAPIのイベント伝播

AutomationAPIのイベント伝播

AutomationAPIの初期化処理

では、SystemManagerから始まる内部の初期化の流れを追ってみます。
以下の図は、SystemManagerから始まる処理の流れを図にしたものです。

AutomationAPI関連図

AutomationAPI関連図

  1. SystemManager内のdocFrameHandler()でMixinに指定されているクラスのinit()メソッドが呼び出されます
    (詳細は前記事Mixinを参照して下さい)。
  2. AutomationManager及び委譲クラス群はMixinに指定されているため、
    SystemManagerのmixin呼び出しを受けて、AutomationManagerと委譲クラス群の処理が実行されます。
  3. 2.のMixinにより各設定が行われた後、画面上に各コンポーネントの描画が行われます。
  4. Automation.delegateClassMapにマッピングされたオブジェクトは、
    ADDEDのタイミングで処理の委譲が行われることになるため、委譲先のイベントとしてRECORDがdispatchされます。
  5. エージェントはこの委譲クラス群(正確にはAutomationManagerより発生される)イベントをListenすることでそのイベント及びイベントのトリガとなったコンポーネントの情報を取得することが可能になります。

ここで注目したいのは2番目の処理になります。AutomationManager及び委譲クラス群の処理に関して、もう少し掘り下げてみます。

AutomationManagerの場合

init()メソッドでは、rootに対してADDEDイベントをListenするイベントハンドラ(childHandler())が定義されます。
これは、SystemManagerをrootする表示オブジェクトにコンポーネントが追加(Event.ADDED)されたときにdispatchされます。
childHandler()は、引数に渡されたコンポーネントから対応するAutomationクラスに定義された委譲クラスのインスタンス化を行い、
Automation.delegateClassMapにそのインスタンスを登録します。

委譲クラス群の場合

init()メソッドでは、Automation.registerDelegateClassを利用してAutomation.delegateClassMapに自身を登録します。
# ここでは自身を登録しているのみで、インスタンス化を行っているわけではありません。
# 委譲クラスのインスタンス化はAutomationManagerのchildHandlerによって行われます。

また、委譲クラスの持つイベント(つまり実体クラスと同様のイベント群)に対しイベントリスナが登録されます。
このイベントリスナは内部でAutomationManager.recordAutomatableEvent()を呼び出します。
# AutomationManager.recordAutomatableEvent()が実行されると、
# AutomationManagerクラスによってRecordEventがDispatchされます。

Automationクラスの場合

実クラスと委譲クラスのMapを保持するAutomationクラスは静的クラスとして設計されており、
初期のアクセス時に内部プロパティdelegateMapを初期化しその値を保持します。

    /**
     *  Registers the component class and delegate class association with Automation.
     * 
     *  @param compClass The component class. 
     * 
     *  @param delegateClass The delegate class associated with the component.
     */
    public static function registerDelegateClass(compClass:Class, delegateClass:Class):void
    {
        if (!delegateClassMap)
            delegateClassMap = {};

        var className:String = getQualifiedClassName(compClass);
        delegateClassMap[className] = delegateClass;
    }

これらの仕組みを組み込んだ上で、AutomationRecordEvent.RECORDをListenするように
エージェントクラスの実装を行う事になります。

この4.から5.の流れは、Flexのヘルプを参照していただくとわかりやすいと思います(Flexのヘルプから)。

エージェントへの操作フロー

エージェントへの操作フロー

次へ続く…

Posted in program | タグ: , , , , | Leave a Comment »