愛と勇気と缶ビール

ふしぎとぼくらはなにをしたらよいか

JavaScriptのテストについて本気出して考えてみた(2)

前回からの続きで。

DOMエミュレーションの戦略

一方で、本物のブラウザを使わずに何らかのJavaScript実行環境でDOMをエミュレートして、その上でテストを走らせよう、という戦略もある。

この分野の大御所はEnv.js(http://www.envjs.com/)ということになっているのだけど、Env.jsのイヤンなところは導入がめんどくさい所である。何がめんどくさいって、antでビルドしなくちゃいけない。テストのためにどの程度の環境構築コストをかけられるかは状況において違うだろうが、例えばJSをメインでやっているエンジニアが「ちょっとテスト環境整えたい」っていう時にantから入れて頑張るだろうか?Javaの経験や、こういうビルドツールの導入/利用の流れに慣れている人だと全然問題ないレベルなんだけど。

というわけで、Env.jsは結構力を入れて開発されたものではあるのだろうけど、僕にとっては「なんかゴツい」「なんかめんどくさい」という感じが拭えないソリューションなのである。もちろん完全に主観です。

あとこれは余談だけど、Env.js発起人のJohn Resigエバンジェリストが "JavaScript Testing Does Not Scale" (http://ejohn.org/blog/javascript-testing-does-not-scale/) という記事で、「jQueryのテストにはRhino + Env.jsを使っていたころもあるけど、今はもう使ってない。TestSwarmに移行したぜHAHAHA」という旨の発言をしている。2009年の記事でかつJohn Resigエバンジェリストのことでもあるので、既に次なるツールのエバンジェリストになってたりするのかもしれないが僕は知らない。ただjQueryのテストに使われなくなったのはそれなりに事情のあることでもあろうので、これをもってEnv.jsの価値を貶める理由にはならない。念のため。



Env.jsとは別に、最近僕が色々試してみているのがNode JSのライブラリとして開発されているjsdom (https://github.com/tmpvar/jsdom)である。これはNode JSの上でDOMをエミュレートするためのライブラリで、Node JSとnpmが入っていればnpm install jsdomで一発でインストールできるのが魅力である。(Node JSとnpm入れる時点で人によっては結構めんどくさくね?っていう意見はあるかもしれない)

jsdomは使ってみた感じEventまわりもちゃんと動くし、node-jquery (https://github.com/coolaj86/node-jquery) を使えばjQueryが動いたりもするし、最近ではローカルのスクリプトなどもloadできるようになった。上記ページを見ると

 require('jsdom').defaultDocumentFeatures = {
   FetchExternalResources   : ['script'], 
   ProcessExternalResources : false,
   MutationEvents           : false,
   QuerySelector            : false
 }

のようにどの機能を使うかの選択もでき、(まだ試していないが)DOM Mutation EventやSelectors APIのサポートも入っているようだ。

jsdomをベースにしてもっと頑張ってエミュレートしちゃおうぜ!というのが Zombie.js (http://zombie.labnotes.org/)で、これは外部ライブラリを利用してhtml5まわりのサポートもしていたり、ちゃんとcookieなども食える上にxhrも扱える。JavaScriptも扱えるMechanizeもどき、というとPerlやRuby界隈の人には分かりやすいかもしれない。用途によっては中々イケそうな感じである。(ちょっとした理由で、僕が現在検討しているJSのテストに使うのは見送った)

首がないけど人間です

Headのあるブラウザを使った自動化、ブラウザ以外での環境でのエミュレーションの他に、「別に本物のブラウザがHeadlessでもいいよね」という発想の元に最近出てきたのが Phantom JS (http://code.google.com/p/phantomjs/)で、これはなんとQtWebkitを使って本物のブラウザ(ただしレンダリングした画面を表示しないのでGUIが必要ない)をCUIから動かしてしまおうという試みである。

Phantom JSはガチでHeadlessに動く本物のブラウザなので、session周りも問題なく動くしxhrも投げ放題である。ただ実際に動かしてみると分かるが、ページをまたいて保存できる状態がString型を入れられるphantom.stateのみなので、ページ遷移を含むテストを書こうとすると例にあるように毎回phantom.stateを見たりphantom.stateに代入したり、要は地味な状態遷移を自分で管理しなければいけない。抽象化を試みようにも、使えるのがphantom.stateだけなので中々厳しい感じである。ちなみにコマンドラインから食わせるJSファイルはどうやらメインループ的なものの中に放りこまれているようで、状態遷移を管理しつつちゃんと最後にphantom.exit()を呼んでやらないとロードしたJSの実行は無限ループする。

とはいえHeadlessで動く、かつエミュレーションでない本物のブラウザなんて今までになかったので、Phantom JSは「DOMのエミュレーション?何それ?それ頑張るとこじゃなくね?」という状況を作り出す可能性を秘めた面白いツールだと思う。APIの充実/改良が待たれる感じである。改良をまたず要望でも投げようかしら。

しかし、Zombie.jsといいPhantom JSといい、何かしら化物っぽい名前をつけているのは欧米の人には"Headless"という言葉からそういった人ならざるものを連想する志向性があるのだろうか?なかなか興味深い。


(つづく)