JUnitでJavaScript
テスト
      Fx-Js-JUnitの紹介
おことわり

●   この発表ではJavaFXの話は
    ほとんど出てきません。
●   JavaScriptの話を延々としま
    す。
●   あらかじめご了承下さい。
誰?

● 名前 : @mike_neck
● 所属 : 無職
  ○ 1日9時間勤務で18時定時で昼1時間の
    休憩に加えて3時間昼寝できる会社探し
    ています。
● 職業 : プログラマー
  ○ Groovy / JavaScript / Java
● ブログ
  ○ mike、mikeなるままに…
本日のテーマ

●   JavaでJavaScriptをテストす
    る
    ○ Fx-Js-JUnitの紹介

    ○ 技術接近遭遇、的な

    ○ 名状しがたい…
ところで…
JavaScriptのテストどう
していますか?
QUnit
jQueryのテストでも使われているシン
プルかつ強力なテストフレームワーク。
Phantom.jsでCUIから操作可能。
JavaScriptでテストを記述。
Selenium
ブラウザーの自動操作ツール。Selenium
Web Driverを用いてUI系のテストが記述
できる。画面がボコボコ立ち上がるのがう
ざい。
JavaでJavaScriptのテス
トが書けて、かつうざくな
い奴が欲しいと思いませ
ん?
そこでFx-Js-JUnitで
すよ!
Fx-Js-JUnitを三行で
説明せよ!
Fx-Js-JUnitを三行で説明せよ!

● JavaFX2.0のWebEngineを用いたテスト
  ツール。
● JUnitで型安全にJavaScriptのテストが
  できる。
● ブラウザーが立ち上がらないのでうざく
  ない!

…ニャル子、あかちゃんつくろ
そうそう、JUnitの説明は
省きますよ
詳しくはWeb + DB プレス
#69のJUnit特集で
Server   JavaFX




JUnit     Test
サンプルテストコード

@ClassRule
                                            @ClassRuleでテ
private static UseFxJsJUnit fxJsJUnit =
                                            スト前にJavaFX
     UseFxJsJUnit
                                            アプリケーション
        .address('http://www.google.com')   を起動
        .identifiedBy('TestClass').get();


private JsJUnit jsJUnit;


@Before                                     JavaScriptのイ
public void setUp () {                      ンターフェースを
     jsJUnit = fxJsJUnit.getTester();       取得
}
サンプルテストコード
                                                    型Longを期
                                                    待するテスト
@Test                                               実行
public void longTest () {
    assertThat(jsJUnit.callLong(Integer.MAX_VALUE + " + 1"),
      is (Integer.MAX_VALUE + 1L));
}
@Test                                                型Personを
public void personTest () {                          期待するテス
    Person person = new Person();                    ト実行
    person.setName("mike");
    person.setAge(35);
    assertThat(jsJUnit.callAs("{name : 'mike', age : '35'}",
        Person.class), is (person));
}
Fx-Js-JUnit
JavaScriptのテストが
カターンゼン

型安全
Fx-Js-JUnit
< `・ω・´ > ヨロシク
The End
…
……
………
すんません
調子こきました
技術
JavaScriptを型安全に取り扱うために

●   JavaFXスレッドの理解
●   並列処理を構成する部材の
    理解
●   JavaScriptオブジェクトから
    Javaオブジェクトへのマッピン
    グ
JavaFXスレッドの理解-1

● アプリケーションを起動した後の部分のコードは
  アプリケーション終了後に実行される

 Application.launch(App.class);
 doSomething();


↑Platform.exit(); の後
に実行される。
JavaFXスレッドの理解-2

● UIを構成するオブジェクトへの操作、結果の取
  得はJavaFXスレッドを介する必要がある。


 WebEngine engine;
 engine.executeScript("1 + 1");

 Platform.runLater(
    { engine.executeScript("1 + 1");}
 );
JavaFXスレッドの理解-3

● UIを構成するオブジェクトはJavaFXスレッド上で
  生成しなければならない

                  JavaFX Thread
             engine = new WebEngine();
 WebEngine

                  Main Thread
                WebEngine engine;
JavaFXスレッドの理解-まとめ

●   JUnitからWebViewを操作するために
    ○   JUnitとは別のスレッドからJavaFXアプリケー
        ションを起動
    ○   別のスレッドに演算させた結果を待機して、
        取得
    ○   JUnitはJavaFXスレッドでインスタンス化され
        たオブジェクトへの参照を取得
並列処理を構成する部材の理解

● java.util.concurrent.ExecutorService
  ○ 別スレッドの処理を簡易に記述
  ○ JavaFXアプリケーションの起動にも
     ちいる
● java.util.concurrent.BlockingQueue<T>
  ○ JavaFXスレッドからのメッセージング
     (値のやり取り)に使用する
● javafx.application.Platform
  ○ JavaFXへの操作を提供
並列処理を構成する部材の理解

詳しい話は下記の書籍を参照。

Java並行処理プログラミング
3,990JPYくらい。
http://goo.gl/UUzc1
JS→Javaマッピング

WebEngineのAPIよりhttp://docs.oracle.
com/javafx/2/api/javafx/scene/web/WebEngine.html
   JavaScript values are represented using the
   obvious Java classes: null becomes Java null; a
   boolean becomes a java.lang.Boolean; and a
   string becomes a java.lang.String. A number
   can be java.lang.Double or a java.lang.Integer,
   depending...If the result is a JavaScript object, it
   is wrapped as an instance of the netscape.
   javascript.JSObject
JS→Javaマッピング

 JavaScript   typeof
                          Java Object
   Object      value
    null      object          null
   false      boolean   java.lang.Boolean
    23        number    java.lang.Integer
    1.10      number    java.lang.Double
  "script"    string    java.lang.String
JS→Javaマッピング

WebEngineのAPIよりhttp://docs.oracle.
com/javafx/2/api/javafx/scene/web/WebEngine.html
   JavaScript values are represented using the
   obvious Java classes: null becomes Java null; a
   boolean becomes a java.lang.Boolean; and a
   string becomes a java.lang.String. A number
   can be java.lang.Double or a java.lang.Integer,
   depending...If the result is a JavaScript object, it
   is wrapped as an instance of the netscape.
   javascript.JSObject
JS→Javaマッピング




 ┌(┌ ^o^)┐ JSObject...
JS→Javaマッピング

Plain Old JavaScript Object (POJSO)なら
JSObject#getMember()でマッピングが可能
{name : "cthuga", str : 80, con : 120, siz :
140, pow : 42}

JSObject cthuga = ...;
assertThat(
  (String)cthuga.getMember("name"),
  is ("cthuga") );
JS→Javaマッピング

SAN値を減少させるオブジェクト…
JS→Javaマッピング

Dateオブジェクト…

JSObject date = ...;
date.getMember("year");

  JSExceptionが発生する
JS→Javaオブジェクト

JavaScriptのDateオブジェクトにはメソッドはある
が、メンバーは存在しない。


                   ←Dateオブジェクトに
                   はメンバーがない



                   ←POJSO
JS→Javaマッピング

ちなみにJavaScriptでちゃんとメンバーの隠蔽化が
なされたオブジェクト…
var Encapsulation = function() {
     var count = 0;
     this.addAndGet = function () {
         count ++;
         return count;
     }
};
var counter = new Encapsulation();
return counter;
JS→Javaマッピング

そういったオブジェクトもメンバーを持ちません。
JS→Javaマッピング


メンバーのないJSObjectを
POJOにマッピングするいい方
法はないか
JS→Javaマッピング


メソッドと戻り値の型情報がわ
かれば大丈夫だ、問題ない
JS→Javaマッピング

テストしたい関数
JS→Javaマッピング

関数を実行する関数を作成
JS→Javaマッピング

関数を実行する関数を実行
JS→Javaマッピング

関数を実行する関数を実行する関数を作る
JS→Javaマッピング

{…}を無名関数化
JS→Javaマッピング

戻り値を既知のメソッドでPOJSO化
JS→Javaマッピング

テスト実行
JS→Javaマッピング

既知の型、メンバーを持つPOJSOを取得




(int) jsObject.getMember("addAndGet");
JS→Javaマッピング

DateはPOJSOにマッピング
JS→Javaマッピング

既知の型とメソッドはアノテーションに記述
JS→Javaマッピング

型安全に実行してassertionできる!
JS→Javaマッピング

equals(java.lang.Object)と
hashCode()メソッドの実装は自己責任で
ね★
JS→Javaマッピング

● プリミティブ型は直接取得してassert
● POJSOはgetMemberメソッド経由で
  POJOにマッピングしてassert
● 特殊なオブジェクトはアノテーションのメ
  タ情報からPOJSOを経由してマッピング
  してassert
Fx-Js-JUnit
JavaScriptのテストが
カターンゼン

型安全
Enjoy JavaScript!
ご静聴ありがとぉ…
…ぉ?
テストは複数同時に実行
 したいですよねぇ
お望みであれば
やってみせますが…
名状しがたい…

SAN値が下がりますよ
def service = Executors.newThreadPool(2)
service.execute {
  Application.launch(App) }
service.execute {
  Application.launch(App) }
名状しがたい…
名状しがたい…
名状しがたい…

複数 + JavaFX で検索
名状しがたい…
名状しがたい…




JavaFXは二度起動
させることはでき
ぬ!
名状しがたい…

● 複数のテストへの対応
 ○   WebEngineを複数立ち上げる
 ○   定期的にポーリングを行なって、
     WebEngineが利用されなくなったら
     終了する
名状しがたい…

● TODOs
 ○   複数のテストへの対応
 ○   ServletコンテナまたはJavaEEコン
     テナの搭載
 ○   GitHubへの公開
 ○   Maven/Ivyレポジトリーへの登録
 ○   他ご要望がありましたら
     @mike_neckまで
Thank you
for your attention

Unit testing JavaScript with JUnit/JavaFX