読者です 読者をやめる 読者になる 読者になる

プログラミング 美徳の不幸

Ruby, Rails, JavaScriptなどのプログラミングまとめ、解説、備忘録。

javascriptをRubyでテストする

独自の方式で数値を文字列にするコードをJavaScriptで書きました。さらに、同様の独自の方式で文字列を数値に戻すコードをRubyで書きました。つまり暗号のようなものです。

その約束ごとはシンプルなので、JavaScriptで暗号化してからRubyで復号化してもとと同じ数値ならOKなんですが、それぞれのコンポーネントに分けて考えると「JavaScriptで適切に暗号化できているか」と「Rubyで適切に復号化できているか」を調べる必要があって、かえって二度手間です。

そこでこういうことをしました。
◯my.encrypt.js

var encrypt = function(n){
  // 数値nを文字列に変換する処理
};
if (typeof module !== undefined){
    module.exports.encrypt = encrypt;
}

これが暗号化を行うJavaScriptのコードです。moduleというのはCommonJSの規格でこれがコンテキストに存在したら、つまりnodeとかで動いていたらモジュールとしてencryptを外部から使えるようにします。

そしてテストのために使うコードがこれ。
◯my.encrypt.test.js

var encrypt = require('./my.encrypt.js').encrypt;
console.log(encrypt('123'));
console.log(encrypt('456'));
console.log(encrypt('7890'));

モジュールを読み込んで標準出力に書き出すというもの。まぁ試しにnode my.encrypt.test.jsとかで動かせば暗号が3つ出てくるはず。

次に復号化するRubyのコード。
◯lib/descrypt.rb

class Descrypt
    self.from("暗号")
        #復号化の処理
    end
end

そして最後に以上をテストするためのコード。
◯spec/descrypt_spec.rb

require './spec_helper'
require './lib/descrypt'

describe "Encrypt" do
  before(:all) do
     node_result = `node my.encrypt.test1.js`
    @encrypted_scores = node_result.split("\n")
  end
  
  it "sample1" do
    Descrypt::from(@encrypted_scores[0]).should eq 123
  end
  以下省略
end

とまぁ、何をやっているかというと要するにnodeのモジュール自体をRubyでテストすることはできないので、標準出力にしてしまってRuby側に取り込んでるんですね。テクニックというほどではなくとも、Rubyの場合は``で外部コマンドを実行すれば標準出力が戻り値で得られるのでこういうことが簡単にできます。

ちなみにこれは綺麗な書き方をしようとしてこうなったんですが、もっと手っ取り早く汎用的にやりたい場合はパイプで結果を渡して、RubyスクリプトからSTDINという組み込み定数を参照するというのも手でしょう。

node my.encrypt.test.js | rspec spec/descrypt_spec.rb 
※spec/descrypt_spec.rbの中ではSTDINを使って結果を受け取るようにする

ただしこの方法はテスト実行者が特殊なイディオムを覚えないといけないので、テスト作成者のしごとを考えると上のようなコードを書くのが望ましいと思います。