カテゴリー別アーカイブ: ツール

NanoTestがマクロ環境以外のテストでのバグも、コンパイラ警告として出力できるようになりました

前回のNanoTestの記事 : テストで検出したバグをコンパイラ警告として出力してくれるHaxeライブラリ、NanoTestを公開しました

このNanoTest、バージョン1.0に更新しました!

これまでのNanoTest

Haxeのマクロ上でテストを実行して、検出したエラーをコンパイラ警告として出力すれば、IDEのコンパイルエラー表示機能を使って表示できるよ。コンパイルエラーと同じように扱われるから、FlashDevelopでもIntelliJ IDEAでも、エラー行の強調とか、エラー行へのジャンプ機能とかが使えるよ。

マクロでテストをすることの重大な欠点

Haxeには出力する言語特有バグとか、挙動の違いとかがあるよ。
あと、各プラットフォーム依存のライブラリとかを使うとマクロを使ってのテストができないよ。

新しいNanoTest

新しいNanoTestではマクロ以外で実行したテストの結果をIDE上に出力することができるようになりました。これで、プラットフォーム依存な内容のテストも簡単にできるようになります。

NanoTestOnFlashDevelopNanoTestOnIntelliJIDEA

しくみ

  1. ターゲットのプラットフォームへコンパイルする
  2. ターゲットのプラットフォーム上でテスト実行して結果をテキストファイルに出力する
  3. マクロでファイルを読み込んで、エラーの情報があれば、コンパイラ警告として出力する

これだけです。とってもシンプル。だけど強力。

これにより、出力対象がNekoだろうと、C++だろうと、C#だろうと、Javaだろうと、JavaScriptだろうと、FlashだろうとIDE上でテストのデバッグができるようになります。

インストール方法

以下のコマンドを入力

haxelib install nanotest

使い方

Githubのsampleフォルダに、FlashDevelop用、Intellij IDEA用のサンプルプロジェクトがあるので、それをみればどうやって使えばいいかはわかると思います。

Nanotest | Github

一応、簡単に解説。

NanoTestRunner.readResult

バージョン1.0で新たに追加されたNanoTestRunner.readResultをマクロから呼び出すことでテキストファイルの内容にしたがって、IDE上でのデバッグが可能になります。

具体的には、hxmlで以下のような指定を行います。

-lib nanotest
--macro nanotest.NanoTestRunner.readResult(テスト結果ファイルのパス, ソースのパスの配列, ラベル)

“テスト結果ファイル”というのは、テストのときに標準出力される内容をファイルにリダイレクトしたものです。NanoTest, haxe.unit, MUnitのNeko出力の出力形式に対応しています。

“ソースのパスの配列”は、テストのコンパイル時に-cpで指定したディレクトリを配列で指定してください。

“ラベル”は任意の文字列です。プラットフォーム名などをラベルにしておくと失敗の警告にラベルが表示されるので、IDE上で表示する際にどのプラットフォームで失敗したのかわかり安くなります。

Haxe/JavaScriptの場合

# test_js.hxml

#1. JSターゲットでコンパイル
-main sample.TestSample
-js bin/test.js
-lib nanotest
-cp src
-cp test
-debug

#2. node.jsで実行して、結果をファイルに出力
--next
-cmd node "bin/test.js" 1>bin/report_js.txt

#3. 出力したファイルをマクロで読み込んで、テストの情報を読み取る
--next
-lib nanotest
--macro nanotest.NanoTestRunner.readResult('bin/report_js.txt', ['test', 'src'], 'JS')

Haxe/Flashの場合

Flashのデバッグをする場合は、flashlog.txtを使用しますので、Flashのデバッグプレーヤーが必要になります。

# test_swf.hxml

#1. SWFに出力
-main sample.TestSample
-swf bin/test.swf
-lib nanotest
-cp src
-cp test
-debug
-D fdb

#2. Flashを起動して、flashlog.txtのテスト結果をコピー。
--next
-cmd swf_debug bin/test.swf bin/report_swf.txt

#3. flashlogのコピーから結果を読み取り
--next
-lib nanotest
--macro nanotest.NanoTestRunner.readResult('bin/report_swf.txt', ['test', 'src'], 'Flash')

Windows用のFlashを起動するバッチファイル(swf_debug.bat)。test_swfと同じ階層に置く。

:: swf_debug.bat

"C:\Program Files (x86)\FlashDevelop\Tools\flexlibs\runtimes\player\11.9\win\FlashPlayerDebugger.exe" %1 
cp "%APPDATA%\Macromedia\Flash Player\Logs\flashlog.txt" %2

MUnitとの連携

NanoTest v1.0のしくみなら、テスト情報の含まれるテキストファイルさえあればコンパイラ警告として出力が可能です。つまり、実際のテストを行うライブラリがNanoTestでなくても構わないわけです。NanoTest v1.0では、MUnitのテスト時に標準出力される失敗行の情報から、コンパイラ警告を出力する機能がついてます(Neko出力にのみ対応)

1. 標準出力をテキストファイルにリダイレクトするようにMUnit実行。

haxelib run munit run 1>bin\test_result.txt

.munitはこんな感じ↓

version=2.1.0
src=test
bin=bin
report=report
hxml=munit.hxml
classPaths=src
resources=resources
templates=null
coveragePackages=null
coverageIgnoredClasses=null

2. 出力されたテキストをNanoTestで読み込み

以下のような、hxmlを実行する。

# nanotest.hxml

-lib nanotest
--macro nanotest.NanoTestRunner.readResult('bin/test_result.txt', ['src','test'], "MUnit")

これで、MUnitでのテスト内容を、IDE上でデバッグできます。

そのほかの変更

パッケージの変更

パッケージ名が変わりました。

shohei909.nanotest.* -> nanotest.*

メソッドチェーンで、テスト失敗時に詳細情報を出力できるように

class SampleCase extends NanoTestCase {
    public function testBasic() {
        var a = [1, 2, 3, 5];
        var b = [2, 2, 3, 3];
        for (i in 0...a.length) {
            assertEquals(a[i], b[i]).label(i);
        }
    }
}

assertから始まるメソッドから、.label()にメソッドチェーンでつなぐと、追加の情報が出力されます。

上の例では、以下のような出力がされるので、失敗したのが配列の0番目と3番目の要素だったことを知ることができます。

Test failed : expected 1 but was 2 [0]
Test failed : expected 5 but was 3 [3]

-D result_exit_code

出力ファイルをNanoTestでreadResultする際に、result_exit_codeのフラグをつけると、テスト失敗時に返り値1でプログラムが終了します。

テストで検出したバグをコンパイラ警告として出力してくれるHaxeライブラリ、NanoTestを公開しました

FlashDevelopcapture-20140201-150704


GUIを使ってテストのデバッグがしたい

Haxeには標準で、haxe.unitというテスト用のライブラリがあります。とてもシンプルなライブラリです。低い敷居でテストを導入できて良いのですが、もの足りないなーと思うところもあります。

何がもの足りないのか?

足りないのはGUIです。グラフィカルなユーザーインタフェースです。黒い画面上に表示されたメッセージを眺めて、ファイルを探して、失敗した行を探して、1つ1つバグを潰していくのは、なんとも骨が折れます。

「ずらっとならんだメッセージをクリックしたら、テスト失敗した行にすぐ飛べる!」とか「失敗行を赤線で示してくれる!」とかそういうGUIがあればもっと楽に、簡単にテストができるわけです。コンパイルエラーでは、エラー行へジャンプする機能も、エラー行をハイライトしてくれる機能もIDEについています。コンパイルエラーと同じように、テストの失敗も表示してくれればデバッグもはかどるわけです。

うれしいことにHaxeのコンパイラはそれを実現できる機能があります。Haxeには、コンパイル前にコードを実行して、その際にコンパイルエラーやコンパイラ警告を出力することができる機能があります。

それが、これ、Compiler Configuration with Macros。いわゆるマクロです。コンパイル中ではなく、コンパイル前に動作するマクロなので、自分はコンパイル前マクロと呼んでいます。今回は、このコンパイル前マクロでつかうテスト用のライブラリNanoTestを作りました。


NanoTest(ナノテスト)

ソースコード:https://github.com/shohei909/NanoTest
ライセンス:MIT Lisence

NanoTest(ナノテスト)の特徴は以下のとおり

  • テストの書き方はhaxe.unitとほぼ同じ。すでにhaxe.unit用に記述したコードがあるならばTestRunnerをNanoTestRunnerに、TestCaseを、NanoTestCaseに置き換えれば、同じように動作します。シンプルなので学習コストも低いです。
  • NanoTestをマクロとして実行することで、テストの失敗をコンパイラ警告やコンパイルエラーとして出力することができます。FlashDevelopだろうとIntelliJ IDEAだろうと、いつもと同じUIでテスト失敗が警告されるので、快適にデバッグをすることができます。

インストール

haxelibをつかってインストールすることが可能です。コンソール上で以下のコマンドを打ち込んでください。

haxelib install nanotest

使い方

基本的な、テストの書き方はHaxeマニュアルのWriting Unit Testsとほぼ同じです。

NanoTestの場合、以下のようなファイルをsample/TestSample.hxとして保存します。

package sample;
import shohei909.nanotest.NanoTestRunner;
import shohei909.nanotest.NanoTestCase;
 
class TestSample {   
    static function main(){
        var r = new NanoTestRunner();
        r.add(new TestFoo());
        r.run();
    }
}
 
class SampleCase extends NanoTestCase {
    public function testBasic(){
        assertEquals( "A", "A" );
    }   
}

これを、以下のようなhxmlファイルでコンパイルして実行すれば、haxe.unitと同じようにテストが出来ます。

-neko testSample.n 
-main TestSample
-lib nanotest

上記のテストをマクロとして実行したい場合、hxmlを以下のように書き変えます。

--no-output
--macro sample.TestSample.main()
-lib nanotest

“–macro”で指定した関数が、コンパイル前に実行させれて、そこでテストの失敗があればコンパイラ警告としてそれが出力されます。

このhxmlを使ってIDEがコンパイルするように設定すれば、IDEがコンパイラ警告としてテスト失敗を出力してくれるので、コンパイルエラーをとりのぞくのと同じようにテストのデバッグを行うことが出来ます。

※ FlashDevelopでhxmlを利用する方法は、ActionScript入門Wiki – FlashDevelopでHaxeプロジェクトを作成するで詳しく紹介されています。

より高度な使い方

テスト失敗を、コンパイル警告ではなくコンパイルエラーとして出力する

NanoTestRunnerのコンストラクタの引数に、NanoTestRunner.error関数を渡しましょう。

こんな風に

var r = new NanoTestRunner(NanoTestRunner.error);

コンパイル警告ではなくコンパイルエラーを出力する設定は、nightlyビルドのような自動ビルドをしたい場合に役に立ちます。つまり、テスト失敗時にコンパイルエラーになるようにしとけば、まちがってユーザーにバグを含むビルドを配布することを防げるので、安心して自動ビルドができます。

unit.haxe.TestCaseには無い関数について

NanoTestCaseは、unit.haxe.TestCaseと同じように使用することが出来ますがunit.haxe.TestCaseにはない追加の関数をもっています。

assertThrows( func:Void->Void, ?isSuccess:Dynamic->Bool, ?p : PosInfos )
funcを実行した場合に例外が投げられることをテストします。さらにisSuccessを設定した場合には、投げられた例外が正しいかどうかを、catchしたオブジェクトをisSuccess関数に渡してテストします。
globalSetup()
テストケースのクラスが複数持っているテスト用のメソッド(“test”ではじまるメソッド)の内、一番最初のメソッドが呼び出される前に呼び出されるメソッド。overrideして使う。
globalTearDown()
テストケースのクラスが複数持っているテスト用のメソッドの内、一番最後のメソッドが呼び出された後に呼び出されるメソッド。overrideして使う。
success( ?p:PosInfos )
テスト成功を出力します。
fail( message:String, ?p:PosInfos )
テスト失敗を出力します。
error( d:Dynamic )
テスト中に発生した例外を出力します。

またTestCaseとは異なり、assertEquals関数がEnumの比較をサポートしています。

注意点

マクロを使ったテストは、あくまでNekoに出力した場合のプログラムをテストしていることになります。FlashやJavaScriptなどその他のターゲットを使用している場合、そのターゲットに依存したコードについてはマクロではテスト出来ません。NanoTestでは、haxe.unit同様、実際にそのターゲットに出力した上で実行してテストするのも可能なので、ターゲット依存のコードについてはマクロを使わずにテストするようにしてください。

更新情報

v0.1.2(2014/02/02 17:29)
swf上で動作させた場合に上手く動かないバグがあったので修正。
v0.1.3(2014/02/02 22:05)
run関数を呼び出す前にassertできるようになりました。これにより非同期のテストが、書きやすくなりました。

右クリックから一発で素材SWCが生成できるFlashDevelopプラグイン作った

cats

[FlashDevelop Assets Packager Plugin]


前置き

だいぶ昔ですが、Flash開発での素材管理についてこんな話題がありました。

「Flash 開発の議論 – あなたは Embed 派、SWC 派、Load 派? – Togetter」

Flash開発者にとって素材管理は悩ましい問題です。

タイムライン中心でFlashを作る場合は、Adobe Flash Professionalの素材管理機能をそのまま使えばいいので、問題になるのはFlashDevelop, FlashBuilder, FDTなどのエディタを使ってコードをガリガリ書いてFlashの開発をする場合です。

いろんな管理方法がありますが、それぞれにメリット、デメリットがあります。

自分が知っている主な方法は5種類です。

これまでの素材管理方法

Flash Professionalを使わない方法

① 素材1つ1つをLoaderで読み込み (ひとつづつLoad派)
例: 「FlashゲームPG講座 For AS3.0【ファイルの読み込みについて】」

② 素材1つ1つを[Embed()]タグで埋め込み (ひとつづつEmbed派)
例: 「Flash ActionScript3で画像を表示する ≪ Walk on apps.」

○ メリット

  • 有料ソフトウェアが要らない
  • 素材の変更がすぐ反映される

× デメリット

  • 素材一つ一つのパスやコードを書かないといけない。

Flash Professionalを使う方法

③素材をSWC化して、ライブラリとして使う。(SWC派)
例: 「SWCを利用したFlash制作の分業ワークフロー:FlashとFlash Builder連携開発 | デベロッパーセンター」

④素材をSWF化して、Loaderで読み込み。(SWF Load派)
例:「Flex で別 SWF のシンボルをロードする方法あれこれ – 俺の成長日記」

⑤素材をSWF化して、[Embed()]タグで埋め込み。(SWF Embed派)
例:「馬鹿全 – Flex と Flash CS3 の ハイブリッド SWF について」

○ メリット

  • コードの記述量が減らせる
  • フォントの範囲指定とか、ファイルの圧縮とかの管理機能がついてくる

× デメリット

  • Flash Proが高い(CS6は定価で84000円)
  • Flash Proが重い
  • 素材を編集した際の再設定がめんどくさい
  • 複数の開発ツールをまたぐので、敷居が高い

自分がよく使ってるのは③です。ただ、Adobe Flash Professionalが必要というのはかなりのネックになります。素材変更するごとにいちいち設定しなおしてパブリッシュするのメンドクサイですし、Flash Proが入ってないところで編集したい場合もあります。とはいえ、この中では一番楽なのでFlash Pro持ってる人はこの素材管理をしてる人が多いと思います。


…でもさ、Flash Proを使わなくてもさ、Embedの記述なんて自動化できるし、SWCの生成だってFlex SDKで出来るんだよね。この際、FlashDevelopのプラグインでも作っちゃった方が楽なんじゃねーの?

ってことで作りました。

FlashDevelop + Assets Packager Pluginでラクラク素材管理

Assets Packager PluginはFlashDevelop4用のプラグインです。

特徴

  • フォルダを、右クリックですぐ使える
  • [Embed]タグを記述したAS3ファイル、SWC、SWFが一発で生成
  • ディレクトリ構造とファイル名がそのままパッケージ名とクラス名に(普通のAS3ファイルといっしょ!)
  • png、gif、jpgをBitmapDataとして埋め込み
  • otf、ttf、ttc、dfontをFontとして埋め込み
  • mp3をSoundとして埋め込み
  • svg、svgzをSpriteとして埋め込み。(v1.5から)
  • as、mxmlはそのままのコードを埋め込み。(v1.2から)
  • txt、xml、swfなどその他すべてのフォーマットはByteArrayとして埋め込み
  • フォントファイルを、右クリック>>[フォントの設定]で埋め込む文字の指定が可能
  • Haxeでも使用可。生成されたSWFを-swf-libで指定。

2分ちょっとでわかる。Assets Packagerのインストール法と使い方。

インストール法はSourceForgeから.fdzダウンロードしてきて、ダブルクリックするだけです。

基本的な使い方

素材を放りこんだフォルダをFlashDevelopのプロジェクトマネージャー上で右クリック>>[素材をパッケージ]を選択するだけで、libフォルダ内に[Embed]を記述したAS3、SWC、SWFの3種類のファイルが一度に生成されます。

例えば、assetsフォルダ内に以下の4つのファイルを置いてパッケージ化した場合

  • assets/image/Background.png
  • assets/sound/SoundEffect.mp3
  • assets/font/Pixcell.ttf
  • assets/text/HelloWorld.txt

次の4つのクラスが自動で生成されます。

  • assets.image.Background (BitmapData)
  • assets.sound.SoundEffect (Sound)
  • assets.font.Pixcell (Font)
  • assets.text.HelloWorld (ByteArray)

これらを利用するためにどのようなコードを書けばいいかはサンプルコードを用意してあります。

SourceForgeでexample.zipをダウンロードしてください。

基本的には、生成されたAS3ファイルかSWCの参照を追加して各クラスをnewするだけです。それぞれ、BitmapData、Sound、Font、ByteArrayとして使うことが出来ます。

package {
	import assets.text.HelloWorld;
	import assets.font.Pixcell;
	import assets.image.Background;
	import assets.sound.SoundEffect;
	import flash.display.*;
	import flash.events.*;
	import flash.media.Sound;
	import flash.text.*;
	import flash.utils.ByteArray;
	
	[SWF(width=480,height=360)]
	public class EmbedTest extends Sprite {
			
		function EmbedTest() {
			//Font(ttf)
			var font:Font = new Pixcell();
			var tf:TextField = new TextField();
			tf.autoSize = "left";
			tf.embedFonts = true;
			tf.selectable = false;
			tf.defaultTextFormat = new TextFormat( font.fontName, 48 );
			
			//ByteArray(txt)
			tf.text = (new HelloWorld() as ByteArray).toString();
			tf.height = tf.textHeight;
			tf.x = (stage.stageWidth - tf.width) / 2;
			tf.y = (stage.stageHeight - tf.height) / 2;
			addChild( tf );
			
			//BitmapData(png)
			var g:Graphics = graphics;
			g.beginBitmapFill( new Background() );
			g.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
			
			//Sound(mp3)
			stage.addEventListener( 
				MouseEvent.CLICK, 
				function( e:Event ):void { new SoundEffect().play(); }
			);
		}
	}
}

結果:[example.swf]

フォントの設定

さらに、フォントファイル(ttf,otf,dfont)を右クリック>>[フォントの設定]をクリックでフォントの埋め込み範囲やフォント名に関する設定を行えます。

フォント_small

詳細設定

他のプラグインと同じようにツール>>環境設定>>AssetsPackagerから各種設定が行えます。
ここで拡張子の設定、各出力のオン/オフ切り替え、出力フォルダの指定ができます。

ライセンス

MITライセンスです。

更新履歴

2013/05/13 v1.5.0
– 拡張子設定”Sprite Extentions”,”MovieClip Extentions”を追加
– ‘.svg’,’.svgz’をSpriteとして対応
2013/04/13 v1.4.0
– 拡張子設定”Bitmap Extentions”を追加
– 拡張子’ttc’をフォントとして対応
– フォント設定に”太字”,”イタリック”を追加。
2013/03/18 v1.3.0
– 設定にcompcのコンパイラオプションを追加。
– コンパイル前のファイル名チェックを追加。
– ファイル名のマルチバイト文字に対応。
2013/03/16 v1.2.2
– 大文字の拡張子が無視されていたのを修正。
2013/03/15 v1.2.0
– .as,.mxmlのファイルをクラスとして埋め込まれるように設定。
– さらに、詳細設定で無視されるファイルの拡張子が指定可能に。
2013/03/14 v1.1.2
-C:以外のボリュームのプロジェクトで使用した際のエラーを修正。