Qunitシリーズ--1.紹介ユニットテスト(上)

55080 ワード

ユニットテストはコードの品質を保証する上で重要であることはよく知られていますが、クライアントコードに対してユニットテストを行うのは難しいことが多いです.JavaScriptコードはバックグラウンドコードやhtmlと密接に結合しているため、真のユニットの概念が欠けているという難しい問題があります.例えばdomの操作では,jqueryのようなクラスライブラリを用いてjsコードを1つのファイルに単独で置くか,埋め込みコードを直接使用するかの実装にかかわらず,テスト可能なユニットはない.
では、ユニットとは何でしょうか.一般的に、ユニットは機能関数であり、同じ入力であり、出力結果は一定である.この場合の関数は、ユニットテストはかなり簡単ですが、domの操作など、特殊な状況を処理する必要がある場合があります.私たちにとって彼は依然として役に立ち、どのコードがユニットに構築されるかを指摘し、対応するテストを行うことができます.
 
ユニットテストの作成
上記の指導思想があれば、私たちが新しい仕事を始め、ユニットテストを導入するときにかなり簡単な仕事です.しかし、本稿で紹介する内容は、既存のコードに対してユニットテストを改善するのに役立ちます.私たちは以下の難題を解決する必要があります.既存のコードを抽出し、重要な部分をテストします.潜在的な問題を発見し、修復します.
既存のコードを抽出して彼を異なる場所に置いて、既存の機能に影響を与えないで、私たちはこの過程を再構築と呼んで、再構築はコード設計を改善するのにかなり役立つ方法です.コードの修正は既存の機能に影響を与える可能性があります.これはユニットテストの重要性を体現しています.彼はあなたの仕事をより保障します.この場合、ユニットテストはまだ行われていないので、手動テストでコードの修正が新しいバグを生じないことを保証する必要があります.私たちは今理論の基礎を持っています.次にしなければならないのは例を探して実践することです.次のコードは、titleのプロパティを含むすべての接続を見つけ、状況に応じて「5 days ago」などの時間が経過したかを示します.
<!DOCTYPE html>

<html>

<head>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <title>Mangled date examples</title>

    <script>

    function prettyDate(time){

        var date = new Date(time || ""),

            diff = (((new Date()).getTime() - date.getTime()) / 1000),

            day_diff = Math.floor(diff / 86400);

 

        if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 )

            return;

 

        return day_diff == 0 && (

                diff < 60 && "just now" ||

                diff < 120 && "1 minute ago" ||

                diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||

                diff < 7200 && "1 hour ago" ||

                diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||

            day_diff == 1 && "Yesterday" ||

            day_diff < 7 && day_diff + " days ago" ||

            day_diff < 31 && Math.ceil( day_diff / 7 ) + " weeks ago";

    }

    window.onload = function() {

        var links = document.getElementsByTagName("a");

        for ( var i = 0; i < links.length; i++ ) {

            if ( links[i].title ) {

                var date = prettyDate(links[i].title);

                if ( date ) {

                    links[i].innerHTML = date;

                }

            }

        }

    };

    </script>

</head>

<body>

 

<ul>

    <li class="entry" id="post57">

        <p>blah blah blah...</p>

        <small class="extra">

            Posted <span class="time"><a href="/2008/01/blah/57/" title="2008-01-28T20:24:17Z"><span>January 28th, 2008</span></a></span>

            by <span class="author"><a href="/john/">John Resig</a></span>

        </small>

    </li>

    <!--     ... -->

</ul>

 

</body>

</html>

コードを実行すると、すべての時間が置き換えられるわけではありません.コードは、ページ内のtitle属性を含むすべての接続をクエリーし、titleに対してprettyDate関数を実行し、関数が結果を返すとリンクのinnerHTML属性を更新します.
 
コードをテスト可能にする
問題は、31日以上の場合、prettyDateはundefinedを返すだけで、リンクの内容は変化しません.仮定によって何が起こったかを見るには、現在の時間をハードコーディングする必要があります.
<!DOCTYPE html>

<html>

<head>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <title>Mangled date examples</title>

    <script>

    function prettyDate(now, time){

        var date = new Date(time || ""),

            diff = (((new Date(now)).getTime() - date.getTime()) / 1000),

            day_diff = Math.floor(diff / 86400);

 

        if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 )

            return;

 

        return day_diff == 0 && (

                diff < 60 && "just now" ||

                diff < 120 && "1 minute ago" ||

                diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||

                diff < 7200 && "1 hour ago" ||

                diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||

            day_diff == 1 && "Yesterday" ||

            day_diff < 7 && day_diff + " days ago" ||

            day_diff < 31 && Math.ceil( day_diff / 7 ) + " weeks ago";

    }

    window.onload = function() {

        var links = document.getElementsByTagName("a");

        for ( var i = 0; i < links.length; i++ ) {

            if ( links[i].title ) {

                var date = prettyDate("2008-01-28T22:25:00Z", links[i].title);

                if ( date ) {

                    links[i].innerHTML = date;

                }

            }

        }

    };

    </script>

</head>

<body>

 

<ul>

    <li class="entry" id="post57">

        <p>blah blah blah...</p>

        <small class="extra">

            Posted <span class="time"><a href="/2008/01/blah/57/" title="2008-01-28T20:24:17Z"><span>January 28th, 2008</span></a></span>

            by <span class="author"><a href="/john/">John Resig</a></span>

        </small>

    </li>

    <--     ... -->

</ul>

 

</body>

</html>

   インスタンスの実行
リンクには「2 hours ago」「Yesterday」などが表示されますが、現在のコードは実際にテスト可能なユニットではありません.コードをさらに改造しない前提で,我々がテストできるのはDOMの変更結果だけである.これで作業できますが、htmlコードの小さな修正でテストが破れる可能性があります.このテストの効果は低いです.
 
リファクタリング:1
彼がユニットテストできるようにコードを再構築する必要があります.私たちは2つの変更をする必要があります:1.パラメータの形式でprettyDate関数に現在の時間を渡して、このようにプログラムの中でnew Dateを使う必要はありません;2.関数を別のファイルに抽出すると、再利用可能になります.
<!DOCTYPE html>

<html>

<head>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <title>Refactored date examples</title>

    <script src="prettydate.js"></script>

    <script>

    window.onload = function() {

        var links = document.getElementsByTagName("a");

        for ( var i = 0; i < links.length; i++ ) {

            if ( links[i].title ) {

                var date = prettyDate("2008-01-28T22:25:00Z", links[i].title);

                if ( date ) {

                    links[i].innerHTML = date;

                }

            }

        }

    };

    </script>

</head>

<body>

 

<ul>

    <li class="entry" id="post57">

        <p>blah blah blah...</p>

        <small class="extra">

            Posted <span class="time"><a href="/2008/01/blah/57/" title="2008-01-28T20:24:17Z"><span>January 28th, 2008</span></a></span>

            by <span class="author"><a href="/john/">John Resig</a></span>

        </small>

    </li>

    <--     ... -->

</ul>

 

</body>

</html>

  prettydate.jsコード:
function prettyDate(now, time){

    var date = new Date(time || ""),

        diff = (((new Date(now)).getTime() - date.getTime()) / 1000),

        day_diff = Math.floor(diff / 86400);

 

    if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 )

        return;

 

    return day_diff == 0 && (

            diff < 60 && "just now" ||

            diff < 120 && "1 minute ago" ||

            diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||

            diff < 7200 && "1 hour ago" ||

            diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||

        day_diff == 1 && "Yesterday" ||

        day_diff < 7 && day_diff + " days ago" ||

        day_diff < 31 && Math.ceil( day_diff / 7 ) + " weeks ago";

}

   インスタンスの実行
 
テストできるものがありますユニットテストをします
<!DOCTYPE html>

<html>

<head>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <title>Refactored date examples</title>

    <script src="prettydate.js"></script>

    <script>

    function test(then, expected) {

        results.total++;

        var result = prettyDate("2008/01/28 22:25:00", then);

        if (result !== expected) {

            results.bad++;

            console.log("Expected " + expected + ", but was " + result);

        }

    }

    var results = {

        total: 0,

        bad: 0

    };

    test("2008/01/28 22:24:30", "just now");

    test("2008/01/28 22:23:30", "1 minute ago");

    test("2008/01/28 21:23:30", "1 hour ago");

    test("2008/01/27 22:23:30", "Yesterday");

    test("2008/01/26 22:23:30", "2 days ago");

    test("2007/01/26 22:23:30", undefined);

    console.log("Of " + results.total + " tests, " + results.bad + " failed, "

        + (results.total - results.bad) + " passed.");

    </script>

</head>

<body>

 

</body>

</html>

インスタンスの実行(firebugやchromeなどのコンソールの使用が許可されていることを確認します)
  
これにより、コンソールを使用して結果を出力する特定のテストアーキテクチャを作成しました.彼はDOMに依存しないので、ブラウザのないJavaScript環境で実行できます.例えばNode.jsまたはRhino.テストに失敗すると、期待値と実績値が表示されます.最後に、失敗と成功の合計数が表示されます.すべてが成功した場合、結果は次のようになります.
Of 6 tests, 0 failed, 6 passed.

失敗した場合:
Expected 2 day ago, but was 2 days ago.



Of 6 tests, 1 failed, 5 passed.

  
特定のソリューションを使用してテストを完了することができますが、既存のテストフレームワークを使用すると、より良い作業を完了することができます.彼は、より良い結果を示し、より多くのコマンドなどを提供してくれます.次の節ではQunitの使用について説明します.
 
出典:http://qunitjs.com/intro/