きよくらの備忘録

「三日坊主と呼ばせない!日記」改め。主にソフトウェア開発関連の話題。

Chutzpah+QUnitでTypeScriptのユニットテストをTypeScriptで書いてみたメモ

ChutzpahとQUnitを使ってTypeScriptのユニットテストをやってみているので、そのあたりを備忘録として*1

 

環境とか前提条件とか

環境は Visual Studio 2013 Update 4を基準にしています。多分ですがUpdate 2あたりでも普通に動くとは思います。Expressでは Chutzpah Test Adapterが入らないと思いますが、今ならCommunityもありますので無償環境で試されたい方はCommunityを利用されると良いのではないでしょうか。

 

また、前提として、ASP.NET 4世代のプロジェクトでの話と思って頂ければと思います。

(というのは、現在プレビューが公開されているVS2015+ASP.NET 5世代ではプロジェクトの構造が変わり、特にjsやtsのコンパイル、テスト周り等の扱いは色々変わってくることが予想されます*2。ただし、VS2015であっても既存のASP.NET 4以前の形式のプロジェクトを扱う場合は、有効なんじゃないかと思ってます*3。)

 

で、Chutzpah+QUnitでTypeScriptのユニットテストですが、実はこのあたりの話は、我らが@chack411さんが過去にblogにまとめられています

こちらのエントリではVS2012について書かれておられますが、大枠は変わっていません。ということで『Chutzpahとは何ぞや』あたりについては、是非、そちらを参照していただければと思います。

 

『じゃあこのエントリいらんやん?』と思われる向きもあろうかと思います。が、実際にプロダクトのコードに対してユニットテストを書こうとすると、もうちょっとだけ設定が必要だったり考慮するべきことがあったりしました。今回はこのあたりについて特に書いてみようと思います。

 

必要なもは『Chutzpah』と『qunitの型定義ファイル』

実際にChutzpahをアダプターとしてQUnitを利用する場合、追加で必要になるのはChutzpah自身と、TypeScriptからQunitを使う際に必要になる型定義ファイルです。

 

Chutzpah Test Adapter for the Test Explorer

VS拡張として提供されている「Chutzpah Test Adapter for the Test Explorer」を検索してインストールします。VSのテストランナーから実行するだけであれば、これのみでOKです。 f:id:kiyokura:20141209233752p:plain

なお、「Chutzpah Test Adapter for the Test Explorer」にはQUnitやJasminなどが同梱されています。追加でインストールする必要はありません。

 

QUnitのTypeScriptの型定義ファイル

TypeScriptでユニットテストを書く場合、QUnitの型定義ファイルが必要になります。 NuGetでqunit.TypeScript.DefinitelyTypedを検索するなり、DefinitelyTypedのリポジトリなりからqunit.d.tsを入手しましょう。どこに配置するか、などは、また後ほど。

 

ソリューションの構成について

実際のプロダクトでテストを書く場合、VSの流儀?ではプロダクトとテストのソリューションを分けることが多いのではないかと思います。ということで、今回はプロジェクトを分けてみます。 サンプルとして、以下の構成でソリューションを作ってみました。

 

  • TsUtSample [ソリューション]
    • TsUtSample.Web [プロダクトのプロジェクト(Webアプリケーション)]
    • TsUtSample.Test [テストのプロジェクト(クラスライブラリ)]

 

また、TsUtSample.WebではjQueryとjQueryUIを利用したコードを書くこととします。そのため、jQueryとその型定義ファイルをNuGetから取り込んでいます。そしてアプリケーションのコードである、app.tsを追加しています。 f:id:kiyokura:20141209233753p:plain

まずはスタートはこんな感じ。

最後に、app.tsにテスト対象のコードとして、こんなコードを書いてみました。

/// <reference path="typings/jquery/jquery.d.ts" />
module App {
    export class Hoge {
        addNameSpan = (selector: string, name: string): void=> {
            $(selector).append('<span>' + name  +'</span>');
        }
    }
}

 

テストプロジェクトへのqunit.d.tsのインストール

テストプロジェクトに、先ほど説明したqunit.d.tsをインストールしておきます。とりあえず今回はNuGetから入れています。こんな感じで入ります。 f:id:kiyokura:20141209233754p:plain

 

テストの記述

実際にテストを書いてみます。 テストプロジェクトにappTest.tsという名前でファイルを追加して、QUnitを利用したテストを書いてみます(テストの内容については深く突っ込まないでください:p)。

test("指定した要素に名前を表示するspanを追加する", function () {

    // #qunit-fixtureにテスト用のDOMツリーを作成
    $("#qunit-fixture").append("<div id=\"target\"></div>");

    var app = new App.Hoge();
    app.addNameSpan("#target", "kiyokura");

    // 雑だけどとりあえずこれでテストOKとする
    var actual = $("#target").children("span").text();
    var expected = "kiyokura";

    equal(actual, expected, "innerTextが'kiyokura'なspanが追加されている");
});

ただし、このままではTypeScriptのコンパイラがエラーが出ます。下記のように赤線が出ます。jQueryQUnit、アプリケーションコードのそれぞれの識別子が解決できないためです。 f:id:kiyokura:20141209233755p:plain

 

referenceの追加

ということで、必要なものを参照するように設定します。このあたりは前述のchackさんのblogにもある通りです。プロジェクトをまたがっている場合でも、ドラッグアンドドロップすれば相対パスで記載してくれます。これでTypeScriptコンパイラのエラーは解消しました。 f:id:kiyokura:20141209233756p:plain

 

テストを実行してみる(※ここではエラーになります)

ここでテストを実行してみます。メニューやショートカット(Ctrl+R , A)などからテストを実行してみましょう。表示されていなければ「テスト エクスプローラー」を表示させておくと良いでしょう。

見出しでネタばれてしていますが、ここではテストは失敗します。詳細を見てみると、どうやら実行時に『$(jQuery)』が解決していないような雰囲気です。 f:id:kiyokura:20141209233757p:plain

 

実行時に必要なライブラリを解決する

ということで、実行時に必要なライブラリの参照を解決してやる必要があります。

ここで、TypeScriptならではの注意点があります。JavaScriptであれば、型定義ファイルと同様に/// <reference path="" />で参照を指定すればよいのですが、TypeScriptの場合、/// <reference path="" />に記述できるのはtsファイルのみです(VSのエディタで見ると、赤線でエラーとして表示されるのがわかります。)。

 

『chutzpah_reference』による参照解決

これに対して、chutzpah側で解決策が用意されています。/// <chutzpah_reference path="" />という代替記法を使って、JavaScriptファイルへの参照を記載します*4

完成版?のテストファイルのソースはこんな感じになります。今回はjQueryだけですが、他に必要なライブラリがあればすべて記載する必要があります。chutzpah_reference

/// <reference path="typings/qunit/qunit.d.ts" />
/// <reference path="../../tsutsample/scripts/app.ts" />
/// <reference path="../../tsutsample/scripts/typings/jquery/jquery.d.ts" />
/// <chutzpah_reference path="../../tsutsample/scripts/jquery-2.1.1.min.js" />

test("指定した要素に名前を表示するspanを追加する", function () {

    // #qunit-fixtureにテスト用のDOMツリーを作成
    $("#qunit-fixture").append("<div id=\"target\"></div>");

    var app = new App.Hoge();
    app.addNameSpan("#target", "kiyokura");

    // 雑だけどとりあえずこれでテストOKとする
    var actual = $("#target").children("span").text();
    var expected = "kiyokura";

    equal(actual, expected, "innerTextが'kiyokura'なspanが追加されている");
});

これで、再度実行すると、見事、テストが通りました。 f:id:kiyokura:20141209233758p:plain

 

参照をまとめる

とりあえずこれでテストは通るようになりましたが、テストのスクリプトのファイルごとに毎回これを書くのは面倒になるかもしれません。この場合は、一つのファイルにまとめ、これを参照することで解決できます。ファイル名は何でも良いのですが、Visual StudioJavaScriptの参照ファイルの名前に合わせて、『_reference.ts』とでもしておきます。

/// <reference path="typings/qunit/qunit.d.ts" />
/// <reference path="../../tsutsample/scripts/app.ts" />
/// <reference path="../../tsutsample/scripts/typings/jquery/jquery.d.ts" />
/// <chutzpah_reference path="../../tsutsample/scripts/jquery-2.1.1.min.js" />

そして、テストスクリプトからはこの_reference.tsを参照するようにします。

/// <reference path="_reference.ts" />

test("指定した要素に名前を表示するspanを追加する", function () {

    // #qunit-fixtureにテスト用のDOMツリーを作成
    $("#qunit-fixture").append("<div id=\"target\"></div>");

    var app = new App.Hoge();
    app.addNameSpan("#target", "kiyokura");

    // 雑だけどとりあえずこれでテストOKとする
    var actual = $("#target").children("span").text();
    var expected = "kiyokura";

    equal(actual, expected, "innerTextが'kiyokura'なspanが追加されている");
});

 

 

(Chutzpahには、Chutzpah.jsonという設定ファイルでこのあたりの参照を管理・設定することができるようなのですが、ちょっと試した感じうまいこと行きませんでした。時間ができたらまた色々と試してみようと思います。)

 

 

まとめ

ということで、Chutzpah+QUnitでTypeScriptのユニットテストをやってみました。まだまだ手探りでやってる所も多く、突っ込みどころ等ありましたら是非是非よろしくお願いいたします。

サンプルのソリューションはgithubに上げています。

*1:プロジェクトが始まったばかりなのでまだ試行錯誤フェーズ

*2:Karma と grunt or gulpで…とかになるのかなーとおぼろげに想像中。

*3:保証はできませんが

*4:https://github.com/mmanela/chutzpah/wiki/Chutzpah-File-References#alternate-reference-syntax