ASP.NET MVC と QUnit で JavaScript の単体テストをおこなう

こちら でご紹介した patterns & practices: Project Silk では、JavaScript の単体テストに jQuery で使われている QUnit が採用されています。JavaScript のニーズが非常に高まっている中、その JavaScript コードのテストをどのようにおこなうか、といったことも Web アプリケーション開発ではしっかりと考えていかなければなりません。

単体テストでは「テストコードを書く」といった作業が発生しますが、一度テストコードを書いておけば、そのテストコードが対象とするコードを変更しても短時間で検証をおこなうことができます。特に JavaScript では、jQuery などの外部ライブラリを使うことが多くなってきており、そういった外部ライブラリのアップデートに起因する、意図しない不具合も起こりえます。

そこで今回は、QUnit を Visual Studio 2010 と ASP.NET MVC プロジェクトで使用する方法をご紹介します。

1. QUnit ライブラリのプロジェクトへの追加

QUnit を手動でプロジェクトに追加することも可能ですが、Visual Studio 2010 では NuGet パッケージとして公開されていますので、NuGet 経由で簡単にプロジェクトに追加することができます。

パッケージ名: QUnit for ASP.NET MVC
ID: QUnit-MVC

a) [ツール] – [Library Package Manager] – [Nanage NuGet Packages for Solution...] の使用

image

b) [ツール] – [Library Package Manager] – [Package Manager Console] の使用

image

上記 (a) または (b) の方法で NuGet 経由でインストールすると、プロジェクトに Script/qunit.jsContent/qunit.css の 2 つのファイルが追加されます。

2. テストコードの準備

続いて、テストしたい JavaScript の関数やオブジェクトなどに対してテストコードを用意します。

テストコードのもっともシンプルな記述の例は下記の通りです。

    1: test("a basic test example", function () {
    2:     ok(true, "this test is fine");
    3:     var value = "hello";
    4:     equal(value, "hello", "We expect value to be hello");
    5: });

test(...) はテストの実行関数です。テストコードでは、ok(...) や equal(...) で値の評価をおこないます。

具体的には、例えば下記のような JavaScript で書かれたクラスがあった場合、このテストコードを書いた JavaScript ファイルをプロジェクトに作成します。(ここではテスト対象のコード MyScript.js と同じ Script フォルダーに MyScript.tests.js として作成しました)

[MyScript.js]

    1: var chack = function (name, age) {
    2:     this.name = name;
    3:     this.age = age;
    4: }
    5:  
    6: chack.prototype = {
    7:     SayName: function () {
    8:         return "My name is " + this.name;
    9:     },
   10:  
   11:     SayAge: function () {
   12:         return "I am " + this.age + " years old.";
   13:     }
   14: }

[MyScript.tests.js]

    1: module("module1", {
    2:     setup: function () {
    3:         var me = new chack("Akira", 42);
    4:         equal(me.SayName(), "My name is Akira", "age testing");
    5:         equal(me.SayAge(), "I am 17 years old.", "age testing");
    6:     }
    7: });
    8:  
    9: test("test for chack", function () {
   10:     expect(2);
   11: });

3. テスト実行用の HTML ページの作成

テストを実行するには、HTML ページをひとつ作成する必要があります。このページの構成やデザインなどは、ほとんど QUnit ライブラリで実装されていますので、マークアップは非常にシンプルです。ここでは tests.htm として下記の通り記述しました。

[tests.htm]

    1: <!DOCTYPE html>
    2: <html>
    3: <head>
    4:     <title>QUnit: JavaScript Unit Testing</title>
    5:     <link href="../Content/qunit.css" rel="stylesheet" type="text/css" />
    6:     <script src="jquery-1.7.1.min.js" type="text/javascript"></script>
    7:     <script src="jquery-ui-1.8.17.min.js" type="text/javascript"></script>
    8:     <script src="qunit.js" type="text/javascript"></script>
    9: </head>
   10: <body>
   11:     <h1 id="qunit-header">QUnit - JavaScript Unit Testing</h1>
   12:     <h2 id="qunit-banner"></h2>
   13:     <div id="qunit-testrunner-toolbar"></div>
   14:     <h2 id="qunit-userAgent"></h2>
   15:     <ol id="qunit-tests"></ol>
   16:     <div id="qunit-fixture">test markup, will be hidden</div>
   17:  
   18:     <!-- Code under test -->
   19:     <script src="MyScript.js" type="text/javascript"></script>
   20:  
   21:     <!-- Unit tests -->
   22:     <script src="MyScript.tests.js" type="text/javascript"></script>    
   23:  
   24: </body>
   25: </html>

5 行目で qunit.css を、8 行目で qunit.js を参照しています。そして、テスト対象の JavaScript コード MyScript.js を 19 行目で指定し、そのテストコード MyScript.tests.js を 22 行目で指定しています。

参考までに、プロジェクト内の Script フォルダーの配置は下記のようになっています。

image

4. テストの実行

テストの実行は、上記の tests.htm をブラウザーで表示するだけです。

image

テストが終了すると下記のような表示になります。MyScript.tests.js を見ていただくとわかるとおり、module1 のテストで SayAge() メソッドの戻り値の期待値と実際の値に相違があるためエラーとなっていることが実行結果から確認できます。

image

5. jQuery カスタム プラグインのテスト例

最後に、jQuery のカスタム プラグインのテスト例をご紹介します。

例えば、下記のようなオブジェクトのサイズを 2 倍に変更する jQuery プラグインがあった場合、

[DoubleSizeMe.js]

    1: (function ($) {
    2:     $.fn.doubleSizeMe = function () {
    3:  
    4:         return this.each(function () {
    5:             var $this = $(this),
    6:                 width = $this.width(),
    7:                 height = $this.height();
    8:  
    9:             $this.width(width * 2);
   10:             $this.height(height * 2);
   11:         });
   12:  
   13:     };
   14:  
   15: })(jQuery);

このテストコードは下記のようになります。

[DoubleSizeMe.js]

    1: module("DoubleSizeMe", {
    2:     setup: function () {
    3:         $('#qunit-fixture').append('<div id="dog"></div>');
    4:         $('#dog').width(100).height(100);
    5:     }
    6: });
    7:  
    8: test("test for DoubleSizeMe", function () {
    9:     expect(2);
   10:     var org_width = $('#dog').width();
   11:     var org_height = $('#dog').height();
   12:  
   13:     $('#dog').doubleSizeMe();
   14:  
   15:     equal($('#dog').width(), org_width * 2, "width testing");
   16:     equal($('#dog').height(), org_height * 2, "height testing");
   17: });

テストの実行結果は下記の通りで、期待された通りの結果となりテストにパスしたことが確認できます。

image

6. まとめ

Visual Studio でも、ここでご紹介したような QUnit などを使用することで JavaScript に対しても容易に単体テストを実施することができます。実際に、こちらのブログポストでご紹介した patterns & practices: Project Silk で提供されているサンプルアプリケーション Mileage Stats でも 204 もの JavaScript 単体テストが QUnit で実装されていますので、ご参考になさってはいかがでしょうか。

QUnit
https://docs.jquery.com/QUnit

Project Silk: Client-Side Web Development for Modern Browsers
https://msdn.microsoft.com/en-us/library/hh396380.aspx

patterns & practices “Project Silk” に見る HTML5 とモダン ブラウザのための Web 開発の今後

https://www.slideshare.net/chack411/patterns-practices-project-silk-html5-web