愛と勇気と缶ビール

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

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

テストにおけるxhrのハンドリングについて

今までの記事は、「ブラウザで動くJavaScriptのテストを難しくしているのはDOMとxhrである」と最初にのたまった割にはDOMのことしか書いてないじゃないか、と鋭い人はちゃんと思ったのではないかと思う。

なのでJavaScriptにおける外部リソース操作の双璧をなすところのxhrについてもちょっと書く。

xhrによる外部リソースの操作を含むアプリのテストを(本物のサーバサイドアプリを使わずに)行う場合の方法は主に二つあると思っていて、

1. テストフレームワークの側で、xhrに対してレスポンスを返すようなモックcontroller(?)を書けるようにしておく
2. xhrそのものをモックオブジェクトにしちゃう


1. はつまり、pushによる自動化を行うようなフレームワークだと何らかの形でWebサーバを起動しているはずなので、その中でxhrから叩くためのcontrollerをユーザが書けるようにしておく、という方法です。確かJSTAPdにあったはず。ローカルでDOMをエミュレートする場合でも、例えばNode JSなどは簡単にhttpサーバを立ち上げられるので、実現は可能です。

2. は、ブラウザ上のXMLHttpRequest(あるいはそれのラッパー)を似たような動作をするが実際にhttpリクエストは投げない何かに置き換えてしまうという方法です。探せばいくらでもありそうですが、例えばSinon.JS (http://sinonjs.org/) などには偽のxhrオブジェクトを返すsinon.useFakeXMLHttpRequest()というAPIが用意されています。jquery-mockjax (https://github.com/appendto/jquery-mockjax/blob/master/demo.html) はちょっと趣が異なり、jQueryの$.ajaxの中身をジャックしているようです。

まとめ

何か色々なJavaScriptのライブラリ/ツールまとめ、みたいな感じになってしまいましたが、僕が言いたいのは「これらのツール使えば簡単にテストができそう!やったね!」みたいなことでは全くないです。

元はといえば、いま会社でかかわっているコンポーネントJavaScript周りの整理をする際にあたって、可能であればテストの仕組みもこの際整えたいなあ、と思って色々試してみた結果を何らかの形で残したかったのと、JSのテスト周りについてちょっと前から考えていたことを自分の頭の中で整理したいなあ、という動機でこの記事は書かれました。

職業としてエンジニアをやる以上、僕は特定の期間内に、特定の水準を満たす成果物を作り上げることでお金をもらっているわけです。決して、テスト手法に関する夏休みの自由研究を行うことでお金をもらっているわけではない。

テストは、何らかの成果物を産み出す過程で、その道のりをより楽なものにするため、その成果物の完成度を高めるため、ひいてはその成果物の保守性を高めるために書いているわけです。テスト以外のコーディングと同じく、テストも限られたリソースの上で、限られた時間で行われる必要があります。

限られたリソース、限られた時間の中で行うテストなのに、そもそもそのテスト用の環境を整えるのにものすごい時間がかかるとか、そのテストの枠組みに慣れるまでに多大な学習コストがかかる、とかでは全然意味がないわけです。個人的には、テスト用ツールは何かの言語のパッケージ管理ツールで一発で入るのが理想です。

加えて、どの部分を重点的にテストしたいか、どの程度までを自動テストによって保証したいか(あるいは出来るか)、どこまでクロスブラウザなどの要因に気を配るかは、作っている対象のモノによって全然違います。例えば、多くのブラウザおよびバージョンの組み合わせをサポート対象としているjQueryのようなライブラリと、そのライブラリの上に構築されたそれほどコード量の多くないアプリケーションのコードでは、なされるべきテストは全く違うものになるでしょう。

単にUIを操作するために何かのライブラリにのっかってJavaScriptを使う、ぐらいのサーバサイドがメインなアプリケーションのテストを、TestSwarmなどを使ってバリバリ頑張って行う必要があるとは僕は思いません。また、UIというのは結局は人間が見て触れるものであるため、テストで「これこれの所にこういう要素があって、そのstyleはこんな感じになっているはず」みたいなことを確認したところで、それは「こういうUIになっていて、ユーザからはこんな風に見えるはず」ということの保証にはほとんどなりません。よりテストの粒度を細かくして、「アニメーション開始時にはこうなっていて、1秒後にはこうなっていて、最後にはこうなっているはず」みたいなテストを書きまくったところでそれは時間の無駄にしかならないでしょう。(UIの「ふるまい」のようなものを宣言的にテストするような枠組みがあれば別かもしれませんが…)


結局そのアプリケーションにおいて勘所となるような部分がどこかを判断し、その部分の動作をどこまでの精度でテストするかを判断するのは僕ら人間なわけです。厳密でさえあればいいテストというわけではもちろんないし(僕は数ヶ月前に無意味に細かいテストを書いて注意されてしまったことがありますが…)、必要な要件を満たしていることを確認できないテストは意味がないし、細かすぎもせず穴もなく、必要十分なテストがいいテストだと僕は思っています。

UIの見栄えのように、テストによる保証があまり実際のユーザ体験の保証にはならないような部分については、いっそ「テストをしない」という選択をとるのも現状では全然アリだと思います。特に、他にリソースを割くべき部分がある場合は。

今回の僕の場合は、DOMの操作がメインであることが分かったのでおそらく敢えてテストをしない方向でいきます。Node JSのjsdom上でホゲホゲする方法を考え途中まで作ってみたりもしましたが、周りの人がNode & npmを導入するコスト、そのテストツールの使い方を覚えるコスト、それの使い勝手、それでテストを行った場合に保証されるものの量と質などから総合的に判断してそれを使うのは止めました。自分ひとりが使うなら構わないのですが、「作ってみたかったから作った」程度のモノに人を巻き込むのはよくないな、と思いました。当たり前ですが。


んでまあ、結論になるんですが、「あなたのプロジェクトにおける適切なテストがどんなものかはあなたにしか分からないのだから、何を使ってどのようにテストするかは自分で考えてね☆」ということです。当たり前かつ月並みですが、ここにも銀の弾丸はないです。ただ、ここで僕が書いた分類や、テストに使えそうなライブラリ/ツールなどが、「さあ、JSのテストをしよう」と思った時に何らかの形でお役に立てば幸いです。



というわけでもう一度





途中まで真面目に書いてたのにひどい感じですね。コラぐらいもうちょっと真面目にやってもいいんじゃないですか。


おわりです。あー楽がしたい。楽にテストがしたい。