JavaScript の spec を RSpec で書く
Ruby 以外のプログラムを書いていると, 「RSpec で spec が書けない」というだけの理由で, 億劫になってしまうことがあります.
RSpec で JavaScript の spec が書ければ... そう思って, やってみました.
まずは実際のコードを説明なしに紹介し, 環境構築手順や, 解説については後述します.
テスト対象 (System Under Test)
今回はこの JavaScript のコードを対象に, spec を書いてみます.
とりあえずは「RSpec で JavaScript の spec が書けるのか」という検証が目的なので, シンプルなもので十分でしょう.
t-wada さんのRSpec の入門とその一歩先へをそのまま JavaScript にしてみたようなものです.
detect メソッドに渡す文字列の中に, コンストラクタに渡された単語が含まれるか, を検証するだけの簡単なオブジェクトです.
$ js Rhino 1.7 release 2 2010 09 15 js> load("message_filter.js") js> var filter = new MessageFilter("foo"); js> filter.detect("foo bar baz"); true js> filter.detect("Hello, World!"); false
spec
上記のコードをテストするための spec です.
MessageFilter というクラスは Ruby 上で定義されているわけではないので, ここでは Symbol 型を利用しています.
これを実行すると, 以下のようになります.
$ rspec -fs message_filter_spec.rb MessageFilter with argument "foo" should detect from "foo bar baz" should detect from "Hello World!" Finished in 0.40217 seconds 2 examples, 0 failures
一応の動作は確認できましたね.
環境の構築
今回は以下のような環境を使用しています.
OS は Ubuntu 10.10 です.
$ ruby -v ruby 1.8.7 (2011-02-18 patchlevel 334) [i686-linux] $ rspec -v 2.5.1 $ gem list # 一部省略 *** LOCAL GEMS *** harmony (0.5.6) johnson (2.0.0.pre3) rspec (2.5.0) rspec-core (2.5.1) stackdeck (0.2.0)
普段は Ruby 1.9.2 を使用しているのですが, 今回使用する harmony という gem の依存ライブラリである johnson が, 1.9.x ではインストールできないようなので, 1.8.7 を使用しています.
RVM を利用して複数の Ruby 環境を切り替えられる環境であれば, さほど問題は無いでしょう.
以下のようにインストールします. (Ruby, RVM のインストールは省略)
$ gem install stackdeck $ gem install johnson -v "2.0.0.pre3" $ gem install harmony $ gem install rspec
harmony のインストール時には, 依存ライブラリである stackdeck と johnson も一緒にインストールされるべきですが, 現在は問題があってうまくできないようです.
とりあえず手動でインストールしておけば問題ありません.
どういう仕組みで動いているのか
Johnson が Ruby 上での JavaScript (SpiderMonkey) の実行環境を提供し, Harmony はそれをラップした DSL, とのことです.
Harmony::Page オブジェクトが .js ファイルを読み込んだコンテキストを保持し. x メソッド (execute_js メソッドのエイリアス) でプログラムを実行することができます.
x メソッドで実行した JavaScript プログラム中, 最後に評価された値が返り値として Ruby に渡されます.
(ただし, オブジェクトは返らないらしい)
問題点
- 可読性が低い
JavaScript のコードを文字列リテラルで書かざるを得ないこともあり, とても読みやすいとは言えないでしょう.
RSpec はメタプログラミングにより "Test as Documentation" (ドキュメントとしてのテスト) を簡単に書かせてくれるはずですが. ここではその力を発揮できていません. - Object の検証ができない
前述のとおり, Harmony は JavaScript の Object 型の値を Ruby に渡してくれません.
JavaScript における Object は, ハッシュ変数として使われることもあり, これを検証できないのは致命的でしょう.
とはいえ, オブジェクトがメソッドを持っていた場合, それを Ruby でどう表現するか, という問題もあり, 解決は難しいでしょう.
上記の理由から, 実際に運用・保守していくのは難しいでしょう.
最近は HTML5 によるスマートフォンアプリ作りに挑戦しようとしているのですが, TDD/BDD のフレームワークに何を使うべきか, で迷っています.
今のところは次作の簡単なフレームワークで検証していますが, さすがにずっと運用するわけにはいかないので, デファクトスタンダードなものが知りたいところです.
いいのを知っている方は是非 @yuya_takeyama まで教えてください.
JavaScript におけるテスト技法については, 2011/03/08 (Tue) に Test.js というイベントでおもしろい話が聞けそうです.
是非参加したいところですが, ATND への参加登録が遅くなったので絶望的な状態です...
この記事を LT する発表者としての参加, なんてのはダメですよねぇ...
Ust で我慢します.