タイトル
テスト駆動JavaScript
著者
Christian Johansen (著), 長尾高弘 (翻訳)
出版社
アスキー・メディアワークス
Amazonで購入する

JavaScript のテストに関して書かれた、体系的な本がやっと出た!という感じにまとめられています。

本書では、JavaScript にスポットを当て、テストしやすい JavaScript のコードとはどんなものか、実際にテスト駆動で JavaScript のコードを書くにはどういう手順で進めていけばよいかについて書かれています。

本書は大まかに、次の4部に分けて解説されています。

  • 第1部: テスト駆動開発
  • 第2部: プログラマのためのJavaScript
  • 第3部: JavaScriptテスト駆動開発の実際
  • 第4部: テストのパターン

第1部では、一般的な自動テストやテスト駆動開発(TDD)の概念を説明しながら、JavaScript 用の単体テストフレームワークを紹介しています。

第2部では、JavaScript という言語をおさらいしながら、大きな特徴である関数クロージャプロトタイプ継承ECMAScript 第五版控えめなJavaScript機能検出(クロスプラットフォーム)について説明を掘り下げています。

第3部では、実際に小さなプロジェクトを開発しながらテスト駆動による JavaScript の開発を体験できるようになっています。AjaxComet によるデータストリーミング、Node.js によるサーバサイド JavaScript、これらを使ったチャットプログラムの作成を体験できるようになっています。

第4部では、モックスタブといったいわゆる単体テストのテクニックや、優れた単体テストを書くためのテスト名の付け方や、振る舞いのテストを書くときにはどう書いたらよいか、わかりやすい単体テストコードを書くためのテクニックが説明されています。

テスト駆動JavaScript』の名にふさわしい内容で、他の言語でも共通する単体テストのお作法も学べる本書は、TDD難民の人にオススメです。

おぼえがきです。

テスト駆動開発(Test-Driven Development)

単体テストの対象は、最も小さな単位である関数になる。テストのエントリポイントは公開されているメソッドからにする。

テスト駆動開発における設計

テスト駆動開発では、「あらかじめ決められた大きな設計」はないが「最初の段階では設計はない」というわけではない。

TDD は、何も無いところから優れた設計を自動的に生み出すわけではなく、作業の進展とともに設計を進化させやすくするのである。TDD は、単体テストに強く依存しているため、他の部分から切り離して単独のコンポーネントに力を注ぐ開発スタイルになる。そのため、コードの疎結合を保ち単一責任の原則を守り、不必要にコードが水ぶくれすることを防ぐために大きな力になる。TDD は設計プロセスをしっかりと制御するため、設計に関する多くの決定をどうしてもそれが必要な時まで先送りすることができる。

本書 P.48

TDD で開発を始める最初は、大きな設計は不要であるが、ある程度最初に時間を割いて設計を行う。最初の設計の時に考えることは、「特定の状況下でコードがどのように振舞わなければならないか単一責任の原則)」、「コンポーネント間でどのように仕事を委譲しあうのかGRASPパターン)」である。

単一責任の原則を尊重する

TDD の単体テストでは、依存コンポーネントのテストをしてはならないので、依存コンポーネントはフェイク(モックやスタブ)に置き換えなければならない。

テストフレームワーク

JavaScript のテストをするための事実上の標準はない。実際、JavaScript は汎用の標準ライブラリというものを持たないので、ブラウザのスクリプティングと直接関係のないプログラミングタスクはどれでも事実上の標準を持たないのである。この状況を改善するために、もともとはサーバーサイド JavaScript の標準化を目指していた CommonJS という活動がある。

本書 P.64

JavaScript のテストを行おうとすると、ブラウザ毎の挙動の違いや JavaScript の実装の違いにより動作が異なってきてしまう。そのような問題を解決しようと、Google 作った JsTestDriver が注目を集めている。

JsTestDriver もいくつかの欠点はあるため、YUI Test との使い分けをしていくとよさそう。

プログラマのための JavaScript

関数の引数

JavaScript は関数を呼び出すときに引数の個数をチェックしない。実引数が渡されなかった仮引数は undefined になる。

スコープと実行コンテキスト

JavaScript には、グローバルスコープと関数スコープの2種類のスコープしかない。関数スコープでは、変数を関数内のどこで宣言しても、関数のどこでも参照することができる。

this キーワード

多くのオブジェクト指向言語で、this はレシーバオブジェクトを指すが、JavaScript ではthis の値は呼び出し元によって決まる。

this は、かっこを受かって関数を呼び出したときに暗黙のうちに設定される。関数として呼び出すとグローバルオブジェクト、メソッドとして呼び出すとその呼出に使ったオブジェクトが this になる

本書 P.104

名前空間

オブジェクトを名前空間として使うには、グローバルスコープでオブジェクトを定義し、関数やオブジェクトをそのオブジェクトのプロパティとして定義すれば良い。

1
2
3
4
5
6
var tddjs = {
  lightbox: { /* ... */ },
  anchorLightbox: function(anchor, options) {
    /* ... */
  }
};

大きなライブラリを作るようなときは、名前空間を構造化したい場合がある。そんなときは、namespace 関数を使うと良い。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var tddjs = (function() {
  function namespace(str) {
    var object = this;
    var levels = str.split(".");

    for (var i = 0, len = levels.length; i < len; i++) {
      if (typeof object[levels[i]] == "undefined") {
        object[levels[i]] = {};
      }
      object = object[levels[i]];
    }
    return object;
  }

  return {
    namespace: namespace
  };
}());

var custome = { namespace: tddjs.namespace };
custome.namespace("dom.event");
/* custome.dom.event  namespace */

控えめなJavaScript

セマンティックマークアップは、文書の構造に関わるものであり、文書の構造だけを対象とする。セマンティックHTMLは、アクセシビリティ向上の可能性を広げるだけでなく、CSS と JavaScript とのフックを増やす。視覚的なスタイルやレイアウトは CSS の領域である。表示に関わる属性や要素は使わないようにすべきだ。動作は、JavaScript の領域であり、外部スクリプトを介して関わるようにすべきだ。

本書 P.185

控えめな JavaScript の7つのルールは次のようになる。

  • 思い込みをするな
  • フック(接点)と関係を見つけよ
  • 反復処理を専用ルーチンに委ねよ
  • ブラウザとユーザーを理解せよ
  • イベントを理解せよ
  • 他者と上手く折り合いをつけよ
  • 次のデベロッパのために仕事をせよ

HTML と JavaScript の結合度を下げるために、イベントハンドラを使うとよい。また、テクニックの一つとして、イベントデリゲーションが推奨されている。

イベントデリゲーションは、ほとんどのユーザイベントがターゲット要素だけでなく、DOM 階層の上位コンテナでも発生することである。

ひとつ一つの要素にイベントハンドラを仕込むのではなく、その上位の要素でハンドリングし、子要素の状態によって処理を管理するようにするとすっきりとしたコードになることが多い。

優れた単体テストを書く

テスト名の付け方として、「いかに」ではなく「何を」と「なぜ」を中心につけるとよい