Java Functional Interface〜JUnitのテストでラムダ式にコード短縮〜

ポイント

テストケースの実装中に同じ処理を関数化して実行するように実装しました。

詳細

具体的には以下の赤い部分を2回書かずにFunctional Interfaceを使用するように実装しました。実装したコードはGitにアップしています。参照しているクラスは同じディレクトリに配置してあります。

/** 自分の周りをチェックするメソッドのテストケース */
@Test
public void testCheckAround() {
//// 本当はメソッド1つにつき1ケースのテストを行うが、小さなテストなので勘弁してください。。。 ////
try {
Method test = this.getPrivateMethod("checkAround", String.class);
Consumer func = str -> {

try {
test.invoke(target, str);

} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {

e.printStackTrace();

fail("アクセス違反です。");
           }
       };
//// サンプルデータ1での検証 ////
func.accept("1010010010");
// テストケース1:周囲にアイテムがあるかの判定
ClientData data = target.getClientData();
assertEquals(true, data.isItem());
// テストケース2:周囲に相手プレーヤがいる化の判定
assertEquals(false, data.isPlayer());
// テストケース3:行動できるスペースにブロックがあるかどうか
       WalkHandler handle = data.getHandler();
assertEquals(true, handle.isOkUp());
assertEquals(true, handle.isOkDown());
assertEquals(true, handle.isOkLeft());
assertEquals(true, handle.isOkRight());
//// サンプルデータ2での検証 ////
func.accept("1020020020");
// テストケース1:周囲にアイテムがあるかの判定
ClientData data2 = target.getClientData();
assertEquals(true, data2.isItem());
// テストケース2:周囲に相手プレーヤがいる化の判定
assertEquals(false, data2.isPlayer());
// テストケース3:行動できるスペースにブロックがあるかどうか
WalkHandler handle2 = data2.getHandler();
assertEquals(false, handle2.isOkUp());
assertEquals(false, handle2.isOkDown());
assertEquals(true, handle2.isOkLeft());
assertEquals(true, handle2.isOkRight());
} catch (SecurityException e) {
e.printStackTrace();
fail("セキュリティ違反です。");
} catch (IllegalArgumentException e) {
e.printStackTrace();
fail("メソッドの引数違反です。");
}
}

引数が1つで、返却値がない場合はConsumerを使用する、他の型の場合はそれぞれに対応するIFを使用するようです。参考にしたのはこちらのサイトです。

ちなみに、デバックをしている時の風景をキャプチャしてみました。

でわでわ。。。


## 関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

JUnitクラスの作成サンプル〜@Before,@Afterの使い方〜

JUnitでのテストクラス作成サンプルです。

ポイントになるのはアノテーションで以下のようになっています。

@BeforeClass: テストクラスの実行時に一度だけ起動するメソッド。
<staticメソッドである必要があります、このメソッドはクラスに1つだけ定義されるべきメソッドだからです。>
@AfterClass: テストクラスの終了時に一度だけ起動するメソッド。
<BeforeClassと同様>

@Before: テストメソッドの実行毎に呼ばれるメソッド
@After:  テストメソッドの終了時に呼ばれるメソッド

シンプルにこれだけです。あとはどのようにクラスを実装するか?になります。

サンプルで実装したクラスはこちらにアップロードしてあります。(Git)

/**
 * ND4JのNd4jクラスを学習のため、テストする
 * @author takunoji
 * 2019/05/24
 */
public class TestNd4j {
    /** テスト対象クラス */
    private static ClientManager target;

    /**
     * テストクラスの実行時に一度だけ起動するメソッド。
     * Afterは終了時に呼ばれる
     */
    @BeforeClass
    public static void init() {
         System.out.println("*** BeforeClass ***");
        target = new ClientManager();
    }

    @AfterClass
    public static void after() {
         System.out.println("*** AfterClass ***");
        target = null;
    }

    /**
     * 
     * @param  取得するメソッドの引数の型
     * @param methodName
     * @return
     */
    private  Method getPrivateMethod(String methodName, Class ... args ) {
        Method method = null;
        try {
            if (args == null) {
                method = target.getClass().getDeclaredMethod(methodName);
            } else {
                method = target.getClass().getDeclaredMethod(methodName, String.class);
            }
            // 公開レベルをテストのために変更する
            method.setAccessible(true);
        } catch (NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
            fail("メソッドの取得に失敗");
        }
        return method;
    }

    /**
     * ClientManagerのコンストラクタで、マッピング用行列を初期化する。
     * 1.初期化時に中身を4で埋める
     * 2.移動した時にMapを拡張するので配列の拡張方法も確認
     */
    @Test
    public void testCreateINDArray() {
        // INT型データの行列を作成する
        INDArray data = Nd4j.create(new int[] {3, 3});
        System.out.println("*** init zeros***");
        System.out.println(data);
        System.out.println("*** putScalar ***");
        System.out.println(data.putScalar(new int[] {2, 1}, 1.0));
        System.out.println("*** init ones ***");
        // 1の値で初期化された配列に全て3を足す
        INDArray reData = Nd4j.ones(new int[] {3, 3}).addi(3);
        System.out.println(reData);
        System.out.println(Nd4j.pad(reData, new int[] {6,  6}, Nd4j.PadMode.CONSTANT));
    }
   ・
   ・
   ・
   ・

こんな感じです、DBにアクセスしたり、テスト対象クラスが別のクラスを読んでいるときは、Mockしてスタブ実装してやります。そうすることで「単体テスト」を行うことができ、他のクラスを修正したからここのクラスも修正。。。なんていう火炎車になるような事態を避けることができます。

ちなみに、テストクラスなので初めに決めた仕様を満たすための検証を行うクラスなのでちゃんと作成すれば、仕様変更があった時などソースを修正して仕様通りに動けば仕様変更は完了になるので初めに実装しておくとあとあと楽になります。

その他、機能拡張、マイグレーションなどの対応にもテストがあれば(テストケースを通ればOKの状態なら)システムの変更なども作業工数が減り、会社の出費(主に人件費)の削減につながるのではないでしょうか?

でわでわ。。。





ND4J 行列の作成、編集 〜JUNITでのAPIテスト(学習)〜

前提

行列を使用して、マッピングをしたいと思っています。単純に自分のいる場所を中心にして、移動するたびに行列の大きさを変更して行くものです。

ちなみにAPI(Application Interface)は使用するメソッドとかクラスのことです。

ND4Jって?

Deep Learning 4J でも使用する行列計算用のフレームワーク(ライブラリ)です。細かい部分は上記のリンク先に記載してあります。(英語)

兎にも角にもコードを書いてみないと始まらないので書きます。

行列の作成

作成したコードはGitにアップしてあります

初めに3x3の行列を作成する。今後は2x3(例外が出ます)とか数値の部分を変更してやれば良い。

INDArray data = Nd4j.create(new int[] {3, 3});
System.out.println("*** init ***");
System.out.println(data);

指定した部分の値を変更する

System.out.println("*** putScalar ***");
System.out.println(data.putScalar(new int[] {2, 1}, 1.0));

行列のサイズを変更する

INDArray reData = Nd4j.ones(new int[] {3, 3});
System.out.println(reData);
System.out.println(Nd4j.pad(reData, new int[] {1,  1}, Nd4j.PadMode.CONSTANT));

<出力したログ>

*** init zeros***
[[0.00,  0.00,  0.00],  
 [0.00,  0.00,  0.00],  
 [0.00,  0.00,  0.00]]
*** putScalar ***
[[0.00,  0.00,  0.00],  
 [0.00,  0.00,  0.00],  
 [0.00,  1.00,  0.00]]
*** init ones ***
[[1.00,  1.00,  1.00],  
 [1.00,  1.00,  1.00],  
 [1.00,  1.00,  1.00]]
[[0.00,  0.00,  0.00,  0.00,  0.00],  
 [0.00,  1.00,  1.00,  1.00,  0.00],  
 [0.00,  1.00,  1.00,  1.00,  0.00],  
 [0.00,  1.00,  1.00,  1.00,  0.00],  
 [0.00,  0.00,  0.00,  0.00,  0.00]]

追記

1で初期化した後に全ての値に3を足す処理

// 1の値で初期化された配列に全て3を足す
INDArray reData = Nd4j.ones(new int[] {3, 3}).addi(3);
System.out.println(reData);

<出力結果>

[[4.00,  4.00,  4.00],  
 [4.00,  4.00,  4.00],  
 [4.00,  4.00,  4.00]]

でわでわ。。。



Java ワンポイント〜Method invoke 引数なしの場合〜

イントロダクション

JUnitでprivateメソッドのテストとか、特定のアノテーションやインターフェースのメソッドを直接呼び出したい時などにMethod.invokeが使えます。最近では言われなくなりましたが「< href="http://sp.e-words.jp/w/AOP.html">AOP」の実装で使われています。例として、特定のメソッドを呼び出す前と、後ろに何かの処理を挟み込む時に使うものです。
ウェブアプリなどではフレームワークとして実装済みのものが多いです。

前提

作成したクラスのprivateメソッドをテストしたい時、targetClass.getClass().getDeclaredMethod()」でテストしたいメソッドを取得、テスト起動!とやることができます。

早い話が

結論から言うと、インスタンスをinvoke()に渡してやれば、おっけ!

サンプルコード

JUnit使用しています。

Method method = null;
try {
method = target.getClass().getDeclaredMethod("createMap");
// 公開レベルをテストのために変更する
method.setAccessible(true);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
boolean isError = false;
try {
System.out.println(method.invoke(target));
} catch (IllegalAccessException e) {
e.printStackTrace();
isError = true;
} catch (IllegalArgumentException e) {
e.printStackTrace();
isError = true;
} catch (InvocationTargetException e) {
e.printStackTrace();
isError = true;
} catch (Exception e) {
e.printStackTrace();
isError = true;
}finally {
if (isError) {
fail("テスト失敗");
}
}

JUNITを設定して、実行してみました。ハローワールドをやっています。

追伸、メソッドをこの様に呼び出すやり方は色々な所で使用出来ます。

一昔前は「AOP」なんて呼んでました。「横断的関心事」とかそんな言葉が残っています。
早い話が、特定のメソッドを呼び出すときの前と後ろに処理を挟み込む技術のことです。(笑)
http://sp.e-words.jp/w/AOP.html

## 関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

JavaFX グラフ描画〜AreaChartを使う〜

イントロダクション

ND4Jでグラフを描いて、2次関数とかを描画するのに良い方法はないかと探しておりました。そんなわけでこのグラフはどうだろうか?

AreaChart

実際に写経して動かしてみました。追加で作成したコードは以下の様にやりました。

<実装コード>

public class AreaChartView extends Parent implements MathKitView {

    /* (non-Javadoc)
     * @see zenryokuservice.mathkit.MathKitView#loadView(javafx.scene.layout.VBox)
     */
    @Override
    public Parent loadView(VBox root) {
        final NumberAxis xAxis = new NumberAxis(1, 31, 1);
        final NumberAxis yAxis = new NumberAxis();
        final AreaChart<Number,Number> ac = 
            new AreaChart<Number,Number>(xAxis,yAxis);
        ac.setTitle("Temperature Monitoring (in Degrees C)");

        XYChart.Series seriesApril= new XYChart.Series();
        seriesApril.setName("April");
        seriesApril.getData().add(new XYChart.Data(1, 4));
        seriesApril.getData().add(new XYChart.Data(3, 10));
        seriesApril.getData().add(new XYChart.Data(6, 15));
        seriesApril.getData().add(new XYChart.Data(9, 8));
        seriesApril.getData().add(new XYChart.Data(12, 5));
        seriesApril.getData().add(new XYChart.Data(15, 18));
        seriesApril.getData().add(new XYChart.Data(18, 15));
        seriesApril.getData().add(new XYChart.Data(21, 13));
        seriesApril.getData().add(new XYChart.Data(24, 19));
        seriesApril.getData().add(new XYChart.Data(27, 21));
        seriesApril.getData().add(new XYChart.Data(30, 21));

        XYChart.Series seriesMay = new XYChart.Series();
        seriesMay.setName("May");
        seriesMay.getData().add(new XYChart.Data(1, 20));
        seriesMay.getData().add(new XYChart.Data(3, 15));
        seriesMay.getData().add(new XYChart.Data(6, 13));
        seriesMay.getData().add(new XYChart.Data(9, 12));
        seriesMay.getData().add(new XYChart.Data(12, 14));
        seriesMay.getData().add(new XYChart.Data(15, 18));
        seriesMay.getData().add(new XYChart.Data(18, 25));
        seriesMay.getData().add(new XYChart.Data(21, 25));
        seriesMay.getData().add(new XYChart.Data(24, 23));
        seriesMay.getData().add(new XYChart.Data(27, 26));
        seriesMay.getData().add(new XYChart.Data(31, 26));
        root.getChildren().add(ac);
        ac.getData().add(seriesMay);
        ac.getData().add(seriesApril);
        return root;
    }
}

AreaChart実行

うーん、データの表示には使えそうだが、今は2次関数を描きたいので別なものを探さないとだな。。。

関係ありませんが、JavaFXでのアプリを作成しました。
余計な音が入っています。

このソースだけでグラフが表示できるのは以前作成した仕組みがあるのでそちらを参照ください。

  1. JavaFX + ND4J 〜グラフ作成の準備〜
  2. JavaFX + ND4J 〜グラフ作成:とりあえず表示〜

でわでわ。。。

関連ページ一覧

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine

JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜


h3 id="eclipse">Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜