ブロックを積みながら(122) Node-RED、自前ノードのユニットテスト、Should

Joseph Halfmoon

前回、Node Test Helper をつかったユニットテストを自前ノードに追加。しかしテスト・フレームワークそのものは定番の Mocha を使っています。そしてAssertionについては Should.js を利用とな。元よりJavaScript素人、目が回ります。少しずつそいつらをかじっていきたいと。

※「ブロックを積みながら」投稿順 index はこちら

※動作確認にはRaspberry Pi 3 model B+のRaspberry Pi OS(32bit)上にインストールした以下を使用しています。

    • Node-RED v2.0.5
Should.js

さてMochaフレームワークにもAssertionのためのAPIは含まれているみたいなのですが、Node Test HelperのExampleプロジェクト内では、Should.js というものをAssertionの記述に使ってました。これを使うと、以下のような感じでAssertionが「読み易くなる」らしいっす。その効果は見た目だけではないようですが、知らんけど。

msg.should.have.property(なんたら…

このAPIの理解なくして今回のユニットテストは書くこと能わず。Should.jsのAPIについては以下にドキュメントがあります。

Should.js

ユニットテストに今回追加の差分

さて、前回は見様見真似でmsgオブジェクトを一つだけ流し込んでテストするようなコードのみだったです。しかしテスト対象たる自前ノード data-check は、複数個のmsgを逐次処理するときに履歴を残しつつ履歴に基づく動作をします。一つだけじゃ意味のあるテストはできません。

そこで今回は以下のようにしました。

    1. 入力msgオブジェクトは3個
    2. 3個の入力オブジェクトを全て処理した3回目のチェックを全クリしたらテストはPASS

まあ、たった3個でも履歴に基づいて処理しておると。他に以下も気になっていたのでそのつもりで処理したいと思います。

    • 浮動小数点数をイコールで見るのは恐れ多いのでそれなりの扱いをしたい

前回までは、入力リテラルの浮動小数をチェックするのに、そのままリテラル数値との一致をみてました。これであれば一致比較も大丈夫なハズですが、浮動小数点数の計算結果はイコールで比較してはいけない、というのはどこかで習ったとおりです。大なりとか小なりとか、こんくらい、といった幅を持たせた比較でないとマズイです。今回は Should.js のAPIドキュメントをみながらその辺もコードしてみました。

 it('should do data-check multi-times', function (done) {
   var flow = [{ id: "n1", type: "data-check", name: "test name",wires:[["n2"]] },
   { id: "n2", type: "helper" }];
   helper.load(datacheckNode, flow, function () {
     var n2 = helper.getNode("n2");
     var n1 = helper.getNode("n1");
     n2.on("input", function (msg) {
       msg.should.have.property('NDATA');
       msg.should.have.property('DATAMAX');
       msg.should.have.property('DATAMIN');
       msg.should.have.property('M2');
       msg.should.have.property('NAME');
       console.log('P0: %f', msg.MEAN);
       msg.NDATA.should.oneOf([1, 2, 3]);
       msg.should.have.property('NDATA', 3);
       console.log('P1: %f', msg.MEAN);
       msg.MEAN.should.be.above(1.23);
       msg.MEAN.should.be.below(1.24);
       msg.MEAN.should.be.within(1.23, 1.24);
//       msg.MEAN.should.be.apploximately(1.235, 0.004);
       done();
     });
     n1.receive({ payload: 1.23 });
     n1.receive({ payload: 1.235 });
     n1.receive({ payload: 1.25 });
   });
 });

前回どおり、n1というノードが被テストノード(data-checkノード)で、n2というノードがn1から送出される結果をチェックするためのhelperノードです。

被テストノード n1 に3個のmsgオブジェクトを上流から流し込んでいるのは以下の部分です。

n1.receive({ payload: 1.23 });
n1.receive({ payload: 1.235 });
n1.receive({ payload: 1.25 });

上記をうけて、n1から流れてくるmsgを「ひろう」のが以下の部分です。//アサーションなどと書いてある部分に、Shouldを使ったAssertionがずらずら並べられてます。

n2.on("input", function (msg) {
  //アサーションなど
  done();
});

上記で done(); までたどり着くとTESTはPASSとなって完了しますが、Assertionが途中でフェイルするといつまでたってもdoneまで落ちてこないようです。するとTimeOutということでエラーが報告されるみたいっす。ホントか?

実機実行結果

今回追加分を含むいまのところの全テストを npm test で処理したところが以下に。

moreTestResults

緑のチェックマークのうち上3つは前回と同じものです。一番下の4個目のチェックが今回追加分。

上記をみるとわかるとおり、console.log はフツーに使うことができてテスト結果の途中に出力を出せます。便利。2か所あるconsole.logのうち上の方の

 console.log('P0: %f', msg.MEAN);

では、計3個ながれてくるmsg に対応した平均値 MEAN が毎回出力されています。しかし、もう1か所あるconsole.log の以下については上記をみると

 console.log('P1: %f', msg.MEAN);

最後、3回目のときの値しか表示されていないのが分かると思います。これは、NDATA(データ点数を保持)をチェックしている2種のコードのうち、以下のoneOfでテストしている方は、1, 2, 3どれが到着しても全て通過させるのにたいして、

 msg.NDATA.should.oneOf([1, 2, 3]);

以下の should.have.property は、明示的に3でないとダメよ、と指定しているので、1や2の回ではここを通過できないためだと思われます。

msg.should.have.property('NDATA', 3);

よって上記の下でチェックしている msg.MEANに関するAssertionは全て3回目のときの値に対してということになるはず。

 msg.MEAN.should.be.above(1.23);
 msg.MEAN.should.be.below(1.24);
 msg.MEAN.should.be.within(1.23, 1.24);
// msg.MEAN.should.be.apploximately(1.235, 0.004);

計算された浮動小数点数との比較ということで、above、below、within を使ってみました。チェックする値は約1.238くらいということで、これらは期待通りな挙動(PASS)をしめしました。

しかしコメントアウトしてある should.be apploximagely()メソッドは中心1.235で誤差0.004と指定したつもりだったのですが、FAILします。なんでだろ~。

ブロックを積みながら(121) Node-RED、自前ノードにユニットテスト追加 へ戻る

ブロックを積みながら(123) Node-RED、contribの地図表示機能を使ってみる へ進む