別の記事が近日公開されます。 これは参照専用です。 ライブラリを使用するために必要なすべての情報は、READMEとコード内のコメントで取得できます。
注目を集める画像:

私は初心者のWeb開発者です。 そして、少し前まで、私は本物のプログラマーがするように働く方法を学びたかった。
これにより、3つの主要な要素を理解しました。
- バージョン管理システムを使用します。
- 有能なコードのコメント。
- TDDまたは少なくともコードの単純な単体テスト。
最初は、 gitの基本を学び、 githubに最初のリポジトリを作成する必要がありました。 2つ目はJsDocを選択しました 。そのため、 ノートパッド++から崇高なテキストに切り替える必要がありました(対応するプラグインのみがありました)。
しかし、私にとっては予想外の3番目の問題で、深刻な困難が生じました。
私は本当にjQueryを尊重しているため(ちなみに、jqのプラグインを作成する最初のリポジトリを開いたため)、ユニットテスト用のフレームワークの選択はQunitで決まり
- Qunitが機能するには、かなり大きなHTMLコードをページに挿入する必要があるため、 メインレイアウトが失われます。 そして、すべてのテスト結果がそこに表示されます。 はい、これは
position:absolute 、opacity:.5 などの松葉杖で修正できますが、フレームワークを扱いたくないので、使用したいです - テストが混在しています。 F5を押すと、何度かテストに合格し、失敗したテストを受け取りました。 そして私のコードには、非同期性、Cookieの操作、Ajaxリクエストはありません。 私が正しく理解している場合、これは、以前の結果に応じて、テストのシーケンスを変更するキラー機能によるものです。失敗したテストが最初にチェックされます。
- 失敗テストは非常に見苦しいです。 qUnitは、ほとんどの場合、渡された引数の1つのtoString()を出力し、2番目の引数は無視します。 時折、2番目のものが表示されますが、diffが正しく機能する場合があります。 diffは非常に複雑な関数であることを理解しており、時々動作することも喜ばしいことですが、Qunitが失敗のたびに引数を表示できないのは謎です。
私はこれが本当に好きではありませんでしたが、大きなおじやおばさんがそのように働いているという認識はあきらめませんでした。 プラグインの開発が終わったら、テスト中に対処しなければならなかったすべての神聖な意味を発見することを望んでいました。 一週間、私は
そして今、彼についてもっと
test.itは、JavaScriptコードをテストするためのフレームワークです。
テキストに興味がない人のために-githubのリポジトリへのリンク: test.it
主な機能:
- コンソールは、結果を表示するために使用されます。
- テストシーケンスは変更されません。
- 受信した引数の配列は、すべてのテストの結果に含まれます。
- テストのグループ化は、ネストのレベルに制限なくサポートされます。
- グループ内で(たとえば、テストの1つで)エラーが発生した場合、残りのコードを中断することなく、結果としてキャッチされて表示されます。
現在実装されているテスト:
- 2つの引数の等価。 QunitからアナログOK 。
- つまり、引数の偽でない結果(NaN、Null、undefined、0、false、[]、 ''ではない)、つまりif()を渡します。 Qunitのequalとほぼ同等 。
簡単なスタート
フレームワークを接続するには-行を追加するだけです
<script src='path/to/testit.js'></script>
<body>タグの最後のそして、明らかに最初のテストを使い始めることができます:
test.it('first test');
テスト -条件の充足をチェックする関数( テストオブジェクトのメソッド) 。
test.it( entity )関数は、 エンティティの存在とその値の非偽性をチェックします。
コンソールを開くと(このAPIを最大限にサポートしているFirebugまたはChrome)、次のように表示されます。

あまりない(:
そして、すべてはtest.done()を呼び出してテストを完了しなかったためです。 やってみましょう。 これで、コードは次のようになります。
test.it('first test'); test.done();
そして、それぞれコンソールで:

つまり、すべてのテストに合格します。
root-ルート要素、またはゼロレベルテストのグループ。 他のグループと同じプロパティがありますが、それらについては後で詳しく説明します。
ルート要素を展開すると、その内部にあるすべてのテストの通過の統計と、実行時間が表示されます。

それは明らかです:
- pass-合格した数
- fail-失敗した数
- error-失敗した実行エラーの数
最終行: pass :コメントなし -テスト。 それを拡張して、さらに詳しく見ていきます。

最初に行うことは、テストに合格したというラベルです。 一般に、それらには3つのタイプがあります。
- 合格 -合格
- 失敗 -失敗
- エラー -残りのコードを失敗させないエラーで終了しました
(例:0または2以上の引数が渡されました)
次の行「argument exist and not false」は、テストに合格するために必要なものの説明です。
そして最後に、受け取った引数の配列。この場合、1つの要素「first test」から
この不快なコメントが表示されないようにするために、テストにコメントを追加します。
test.it('first test'); test.comment(' '); test.done();
結果は次のようになります。

しかし、私たちが書いたすべては、原則として、特に何もテストしませんでした。 状況を修正して、実際のテストを追加しましょう。
test.it('first test'); test.comment(' '); var Me = {name:'Titulus',lastName:'Desiderio'}; test.it(Me); test.comment(' ?'); test.done();
コンソールで:

2番目のテストをより詳細に検討できます。 それを展開すると、引数の配列内の唯一の引数がオブジェクトになります。

ご覧のとおり、テストでは、渡された唯一の引数の値の有無のみをチェックします。 しかし、これは、このオブジェクトを覗くのを妨げないことがあります。これは、送信した内容を再度思い出させ、場合によっては有用な追加情報を受け取るためです。
前のテストは正常に完了しました。タスクをさらに難しく設定しましょう。
test.it('first test'); test.comment(' '); var Me = {name:'Titulus',lastName:'Desiderio'}; test.it(Me); test.comment(' ?'); test.it(Me.habr); test.comment('?'); test.done();

お気づきのように、失敗したテスト、および対応する失敗したグループ(ルート)はデフォルトで展開されました。
ところで、引数の配列のおかげで、テストが失敗した理由がすぐにわかります-渡された引数は定義されていません。
今では状況を修正するために残っています:
test.it('first test'); test.comment(' '); var Me = {name:'Titulus',lastName:'Desiderio'}; test.it(Me); test.comment(' ?'); Me.habr = '!'; test.it(Me.habr); test.comment('?'); test.done();
そして再び古い写真!

タスクを複雑にしましょう。 存在および偽りをチェックする代わりに、値の正確さをチェックします。
test.it('first test'); test.comment(' '); var Me = {name:'Titulus',lastName:'Desiderio'}; test.it(Me); test.comment(' ?'); Me.habr = '!'; test.it(Me.habr); test.comment('?'); test.it(Me.habr,'habrahabr.ru'); test.comment(' '); test.done();
関数test.it( entity1、entity2 ) -entity1とentity2の等価性をチェックします。
コンソールを見てみましょう。

テストは失敗しましたが、これは予想どおりです。 結果を見ると、失敗の理由は明らかです。 修正中
Me.habr = '!';
に Me.habr = 'habrahabr.ru';
私たちは再び得る

もっと深くする必要がある
上記のグループを理解します。
グループ -
- テスト(またはグループ)のセット。
- このコレクションが作成するテストオブジェクトのメソッド。
- このセット自体はJavaScriptオブジェクトの形式です。
テストとグループの配列に加えて、合格、失敗、エラーの原因となったテスト(またはグループ)の統計、およびそれらの実行に費やされた時間を保持します。
次のコードを検討してください。
test.it(2>1); test.comment(' ?'); test.group(' ',function(){ test.it(2>1); test.comment(' ?'); }); test.done();
test.it(2> 1); そして、すべてが明確ですが、 test.groupは何をしますか?
関数test.group( groupname 、 fun ) -テスト、他のグループ、および他のコード用の新しいサブグループを作成します。 名前はgroupname引数から取得されます 。 fun関数は実行を試みますが、その中でエラーが発生しても、残りのコードは中断されません。 エラーは、このグループのエラーフィールドに配置されます 。
ルートを明らかにしましょう:

ここでは、 最初のグループであるグループが rootと同じ方法でフレーム化されており、名前だけが私たちが尋ねたものです。
それも明らかにします。

ルートとの特別な違いはなく、そうすべきではありません。
ここでは、 ルートとグループの統計にのみ注意を払う必要があります。
! 重要なポイント:統計では、特定のレベルの結果のみが表示されます。 2つのテストを記述したが、テストの統計でルートに合格したテストは1つだけだとします。
さらにテストを追加します。
test.it(2>1); test.comment(' ?'); test.group(' ',function(){ test.it(2>1); test.comment(' ?'); test.it(1, Number(1)); test.comment(' '); test.it(habr); test.comment(' ?'); test.it(2+2,4); test.comment(' '); }); test.it(1<2); test.comment(' ?'); test.done();
そして見る

2 + 2 = 4のテストも実行されなかった。これは、 habrを使用した以前のテストがReferenceErrorエラーのために実行されなかったためであり、テスト前に統計の下にきれいに表示された。 しかし同時に、 1 <2の最後のテストは合格です。これは、グループ外でエラーが発生したためです。
エラー処理は、今日自分が設定した優先タスクの1つです。 したがって、次のリリース後にこの例の関連性が失われても驚かないでください。 しかし、プログラムを異常終了させずにエラーをキャッチするという主な考えは残っています。
そして、グループに関する最後の瞬間。 マルチレベルのネスト!

test.group('need',function(){ test.group('to',function(){ test.group('go',function(){ test.group('deeper',function(){ test.it('bye habr'); test.comment('bye bye'); }); }); }); }); test.done();

ボンネットの下
すべてのコードはgithubで利用できるため、それを読んだり、コメントしたり、フォークしたり、プルリクエストを提供したりできます。 MITライセンス 。ただし、 WTFPLへの切り替えを考えています。
ゼロレベルのグループに対応するオブジェクトであるtest.rootについて詳しく説明します。 テストがそれを埋めてから、 _printConsole()がそれを解析し、このすべての美しさをもたらします。
グループを使用した最初の例のtest.root:
{ "type": "group", "name": "root", "status": "pass", "time": 7, "result": { "tests": { "passed": 1, "failed": 0, "error": 0, "total": 1 }, "groups": { "passed": 1, "failed": 0, "error": 0, "total": 1 } }, "stack": [ { "type": "test", "status": "pass", "comment": " ?", "description": "argument exist and not false", "time": 0, "entity": [ true ] }, { "type": "group", "name": " ", "status": "pass", "time": 1, "result": { "tests": { "passed": 1, "failed": 0, "error": 0, "total": 1 }, "groups": { "passed": 0, "failed": 0, "error": 0, "total": 0 } }, "stack": [ { "type": "test", "status": "pass", "comment": " ?", "description": "argument exist and not false", "time": 0, "entity": [ true ] } ] } ] }
ところで、はい。 私は非常に恥ずかしいですが、サードパーティのコードの一部があります-deepCompare()関数は外部からアクセスできません。 任意のタイプの2つの引数を比較します。 ここで取った 。
また、マルチレベルのネスティングを実装するヒントについて@mkharitonovに感謝します。
コインの裏側
もちろん、欠点もあります。 深刻なものもそうでないものもあります。 オープンソースのコードなので、コミュニティがそれらを最小限に抑えたり、それらを利点に変えたりするのに役立つことを願っています。
キー:
- クロスブラウザではありません。 コンソールAPIは、実際にはGoogle Chrome(およびクロムベースのその他)とfirefoxのFirebugプラグインのみをサポートしています。 彼らはSafariとも言いますが、私はチェックするAppleデバイスを持っていません。
- 1つのテストグループを個別に実行する方法はありません。
松葉杖があります-test.done()をコード全体の最後ではなく、テストが必要なグループの最後に置きます。 しかし、これは松葉杖であり、必要なすべての機能を備えているわけではありません。
決定的に
- 現在、差分はなく、これは解決可能です。
- ajaxのテストはありません。 これもまた解決可能です。
次は?
そして、上記の統計出力の変更があります。
エラー処理と出力の改善。
テスト出力の改善-失敗したテストの番号付けとヒントが追加されます。
新しいテストtest.them 、 test.type 、 test.types 、 test.timeが追加されます。 それらについての詳細はREADMEで読むことができます。
前のセクションで言及した欠陥は修正されます。
そして、もちろん、最適化。
もう一度githubのリポジトリへのリンク: test.it
PSカルマが十分になり次第、投稿はハブ「I PR」に転送されます。