Jasmine単体テストの概要

Jasmineは、webアプリの単体テスト用の最も人気のあるJSライブラリです。 初心者向けに設計されたこのチュートリアルでは、Jasmineを使用したテストの迅速かつ完全なガイドを紹介します。

JavaScriptのための一般的な動作駆動型テストフレームワークであるJasmineを紹介します。 また、コード内のバグを簡単にチェックするのに役立つJasmineを使用して単体テストを記述する方法に関する簡単な実用的な例も表示されます。

簡単に言えば、テストスイート、仕様、期待を書く方法と、組み込みのJasmineマッチャーを適用する方法、または独自のカスタムマッチャーを構築する方法を見ていきます

また、より複雑なコードベースのテストを整理するためにスイートをグループ化する方法も見ていきます。

Jasmineの紹介

Jasmineは、javascriptアプリケーションを単体テストするための非常に一般的なJavaScriptの動作駆動型開発(BDDでは、実際のコードを書く前にテストを書 これは、同期コードと非同期コードの両方の自動テストを実行するために使用できるユーティリティを提供します。Jasmineには次のような多くの機能があります。

  • これは高速で、オーバーヘッドが低く、外部依存関係はありません。
  • これは、電池が含まれているライブラリだし、あなたのコードをテストするために必要なすべてを提供しています。
  • ノードとブラウザの両方で使用できます。
  • PythonやRubyなどの他の言語でも使用できます。
  • DOMは必要ありません。
  • これは、クリーンで理解しやすい構文と豊かで簡単なAPIを提供します。
  • 私たちは、テストと期待される結果を記述するために自然言語を使用することができます。

Jasmineは、permissive MITライセンスの下で利用可能なオープンソースのツールです。 この記事を書いている時点で、最新のメジャーバージョンはJasmine3.0で、新機能といくつかの重大な変更を提供しています。 Jasmineの2.99リリースでは、バージョン3.0で異なる動作を持つスイートに異なる非推奨警告が提供され、開発者が新しいバージョンに移行しやすくなります。新しい機能と重大な変更点については、このドキュメントから読むことができます。

Jasmineの使い方

Jasmineをさまざまな方法で使うことができます:古い方法では、<script>タグを使用してJasmineコアとテストファイルの両方を含めることにより、

  • js、
  • ノードのライブラリとして。js、
  • Gulpのようなビルドシステムの一部として。jsまたはGrunt。また、jasmineを使用してPythonコードをテストすることもできますjasmine-pyこれはPyPIからpip install jasmineコマンドを使用してインストールできます。 このパッケージには、プロジェクトのJasmineスイートを提供して実行するwebサーバーと、テストと継続的な統合を実行するためのCLIスクリプトの両方が含まれJasmineは、Gemfileにgem 'jasmine'bundle installを実行することでインストールできるjasmine-gemを介してRubyプロジェ これには、テストを提供して実行するためのサーバー、CLIスクリプト、Ruby on Railsプロジェクトのジェネレータが含まれています。ここでは、JavascriptでJasmineを使用する方法に焦点を当ててみましょう:

    スタンドアロンJasmineの使用

    まず、リリースページからJasmineの最新バージョンをダウンロードします。

    次に、zipファイルを、できればテストするプロジェクトのフォルフォルダには、デフォルトのファイルとフォルダの束が含まれます。

    /src:テストするソースファイルが含まれています。 これは、プロジェクトのフォルダを既に設定している場合は削除されるか、ソースコードをホストするために適切な場合にも使用できます。p>

    /lib:コアJasmineファイルが含まれています。p>

    /spec:あなたが書くつもりのテストが含まれています。p>

    SpecRunner.htmlSpecRunner.htmlファイルの内容です:

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>Jasmine Spec Runner v3.2.1</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-3.2.1/jasmine_favicon.png"> <link rel="stylesheet" href="lib/jasmine-3.2.1/jasmine.css"> <script src="lib/jasmine-3.2.1/jasmine.js"></script> <script src="lib/jasmine-3.2.1/jasmine-html.js"></script> <script src="lib/jasmine-3.2.1/boot.js"></script> <!-- include source files here... --> <script src="src/Player.js"></script> <script src="src/Song.js"></script> <!-- include spec files here... --> <script src="spec/SpecHelper.js"></script> <script src="spec/PlayerSpec.js"></script></head><body></body></html>

    /src/specフォルダから含まれるファイルを変更する必要があることに注意してください。…..Jasmineをライブラリとして使用する

    Jasmineをプロジェクト内のライブラリとして使用することもできます。 たとえば、次のコードはJasmineをインポートして実行します。

    var Jasmine = require('jasmine');var jasmine = new Jasmine();jasmine.loadConfigFile('spec/support/jasmine.json');jasmine.execute();

    最初にJasmineを必要とし、loadConfigFile()spec/support/jasmine.jsonパスから利用可能な設定ファイルをロードし、最後にJasmineを実行します。CLIからJasmineを使用することもできます。JASMINEテストを簡単に実行し、デフォルトで結果を端末に出力することができます。最初に次のコマンドを実行してJasmineをグローバルにインストールします。

    npm install -g jasmine

    npm設定に応じて、npmパッケージをグローバルにインストー

    次に、プロジェクトのフォルダを作成し、その中に移動します。

    $ mkdir jasmine-project $ cd jasmine-project

    次に、次のコマンドを実行してJasmineのプロジェクトを初期化します。

    このコマンドは、単にspecフォルダとJSON設定ファイルを作成します。 これはdirコマンドの出力です:

    .└── spec └── support └── jasmine.json2 directories, 1 file

    これはデフォルトのjasmine.jsonファイルの内容です:

    { "spec_dir": "spec", "spec_files": pec.js" ], "helpers": , "stopSpecOnExpectationFailure": false, "random": true}
    • { "spec_dir": "spec", "spec_files": pec.js" ], "helpers": , "stopSpecOnExpectationFailure": false, "random": true}
      • .└── spec └── support └── jasmine.json2 directories, 1 file

        これはデフォルトのjasmine.jsonファイルの内容です:

        { "spec_dir": "spec", "spec_files": pec.js" ], "helpers": , "stopSpecOnExpectationFailure": false, "random": true}
        • :jasmineがテストファイルを探す場所を指定します。
        • spec_files:テストファイルのパターンを指定します。
        • helpers:Jasmineがヘルパーファイルを探す場所を指定します。 ヘルパーファイルは仕様の前に実行され、カスタムマッチャーを定義するために使用できます。
        • stopSpecOnExpectationFailure:trueに設定すると、期待の最初の失敗時にすぐに仕様を停止します(--stop-on-failureを介してCLIオプションとして使用できます)。
        • random:trueに設定すると、Jasmineはテストケースを擬似ランダムに実行します(--randomを介してCLIオプションとして使用できます)。

        spec_fileshelpers配列には、Bashで作業するときにファイルのセットを指定するために通常使用するパターjasmine.jsonjasmine --configオプションを使用してカスタムの場所を指定するだけ公式ドキュメントからより多くのCLIオプションを見つけることができます。

        Jasmineの理解

        このセクションでは、スイート、仕様、期待、マッチャー、スパイなどのJasmineテストの基本的な要素について学びます。

        プロジェクトのフォルダで、次のコマンドを実行して新しいノードモジュールを初期化します。

        これにより、デフォルト情報を含むpackage.jsonファイルが作成されます。

        { "name": "jasmine-project", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": , "author": "", "license": "ISC"}

        次に、index.jsファイルを作成し、次のコードを追加します。

        index.jsファイルを作成し、次のコードを追加します。

        function fibonacci(n){ if (n === 1) { return ; } else { var s = fibonacci(n - 1); s.push(s + s); return s; }}function isPrime(num){ for (let i = 2; i < num; i++) if (num % i === 0) return false; return num !== 1 && num !== 0;}function isEven(n) { return n % 2 == 0;}function isOdd(n) { return Math.abs(n % 2) == 1;}function toLowerCase(str){ return str.toLowerCase();}function toUpperCase(str){ return str.toUpperCase();}function contains(str, substring, fromIndex){ return str.indexOf(substring, fromIndex) !== -1;}function repeat(str, n){ return (new Array(n + 1)).join(str);}module.exports = { fibonacci: fibonacci, isPrime: isPrime, isEven: isEven, isOdd: isOdd, toLowerCase: toLowerCase, toUpperCase: toUpperCase, contains: contains, repeat: repeat};

        スイート

        スイートは、一連の仕様またはテストケースをグループ化します。 これは、通常、オブジェクト/クラスまたは関数によってカプセル化されるJavaScriptコードの特定の動作をテストするために使用されます。 これは、テストスイートのタイトルとテストスイートの実際のコードを実装する関数の2つのパラメータを取るJasmineグローバル関数describe()を使用し

        最初のテストスイートを作成することから始めましょう。 specMyJSUtilitiesSpec.jsファイルを作成し、次のように追加します。

        describe("MyJSUtilities", function() { /* ... */ });

        MyJSUtilitiesは、この最

        スイートをグループ化してネストする方法

        テストのセットをよりよく整理し、正確に記述するために、トップレベルのスイート内にスイートをネストすることができます。 たとえば、MyJSUtilitiesスイートに二つのスイートを追加しましょう。

        describe("String Utils", function() { /*...*/});describe("Math Utils", function() { /*...*/});

        Math Utilsスイート内では、二つのネストされたスイートも追加しましょう。

        describe("Basic Math Utils", function() { /* ... */ }); describe("Advanced Math Utils", function() { /* ... */ });

        関連するテストをString Utils、Basic Math Utils、Advanced Math Utilsのテストにグループ化し、トップレベルのテストスイート内に入れ子にしています。”マイ-ジュスティリティ” これにより、フォルダの構造に似たツリーとして仕様が構成されます。

        ネスト構造がレポートに表示され、失敗したテストを簡単に見つけることができます。

        スイートを除外する方法

        関数xdescribe()

        スイートを除外する方法

        関数xdescribe()describe()x関数に追加するだけで、既存のスイートをすばやく無効にできます。p>

        xdescribe()関数内の仕様は保留中とマークされ、レポートでは実行されません。

        Specs

        specは、テストスイートに属するテストケースを宣言します。 これは、Jasmineグローバル関数it()を呼び出すことによって行われます。

        仕様には、一つ以上の期待が含まれている可能性があります。 各期待値は、単にtruefalsetrueでなければなりません。

        文字列Utilsスイート内で、次の仕様を追加します。

        describe("String Utils", function() { it("should be able to lower case a string",function() { /*...*/ }); it("should be able to upper case a string",function() { /*...*/ }); it("should be able to confirm if a string contains a substring",function() { /*...*/ }); it("should be able repeat a string multiple times",function() { /*...*/ });});

        基本的な数学Utilsスイート内で、いくつかの仕様を追加しましょう。

        describe("Basic Math Utils", function() { it("should be able to tell if a number is even",function() { /*...*/ }); it("should be able to tell if a number is odd",function() { /*...*/ }); });

        高度な数学Utils:

        describe("Advanced Math Utils", function() { it("should be able to tell if a number is prime",function() { /*...*/ }); it("should be able to calculate the fibonacci of a number",function() { /*...*/ }); });

        仕様を除外する方法

        スイートと同様に、xit()it()仕様を一時的に無効にし、仕様を保留中としてマークします。

        Expectations

        Expectationsは、実際と呼ばれる値を取るexpect()関数を使用して作成されます(これは値、式、変数、関数、オブジェクトなどです。). 期待は仕様を構成し、開発者が実行するコードの特定の単位から期待するものを定義するために(連鎖を介して)マッチャー関数とともに使用されます。

        マッチャー関数は、実際の値(expect()関数に渡されます)と期待値(マッチャーにパラメータとして直接渡されます)を比較し、trueまたはfalseを返しまp>

        expect()notキーワードを使用できます。

        この例の仕様を実装しましょう。 ここでは、expect()nothing()マッチャーと一緒に使用します。 この時点では何も期待していないので、これはすべての仕様を渡します。p>

        describe("MyJSUtilities", function() {describe(">String Utils", function() { it("should be able to lower case a string",function() { expect().nothing(); }); it("should be able to upper case a string",function() { expect().nothing(); }); it("should be able to confirm if a string contains a substring",function() { expect().nothing(); }); it("should be able repeat a string multiple times",function() { expect().nothing(); }); });describe("Math Utils", function() { describe("Basic Math Utils", function() { it("should be able to tell if a number is even",function() { expect().nothing(); }); it("should be able to tell if a number is odd",function() { expect().nothing(); }); }); describe("Advanced Math Utils", function() { it("should be able to tell if a number is prime",function() { expect().nothing(); }); it("should be able to calculate the fibonacci of a number",function() { expect().nothing(); }); }); });});

        これは、この時点での結果のスクリーンショットです:p>

        私たちは8つの渡された仕様とゼロの失敗を持っています。

        組み込みのマッチャーを使用するか、特定のニーズに合わせて独自のカスタムマッチャーを作成することができます。

        ビルトインマッチャー

        Jasmineは、ビルトインマッチャーの豊富なセットを提供します。 のは、重要なもののいくつかを見てみましょう:p>

        • toBe()アイデンティティのテストのために、
        • toBeNull()null
        • toBeUndefined()/toBeDefined()null
        • toBeUndefined()/toBeDefined()toBeUndefined()/toBeDefined()toBeNull()nullnan(数値ではない)のテスト用
        • toEqual()
        • toBeNaN()
        • toEqual()
        • toBeNaN()
        • toEqual()
        • toEqual()
        • toEqual()
        • toEqual()
        • toBeFalsy()/toBeTruthy()虚偽/真実などのテストのための。あなたはdocsからmatchersの完全なリストを見つけることができます。

          適切な場合は、これらのマッチャーのいくつかを使用して仕様を実装しましょう。 まず、MyJSUtilitiesSpec.jsファイルでテストしている関数をインポートします。

        const utils = require("../index.js");

        次に、文字列Utils suiteから始め、適切な期待値でexpect().nothing()toLowerCase()メソッドが最初に定義され、次に小文字の文字列を返すことが期待されます。

        it("should be able to lower case a string",function() { expect(utils.toLowerCase).toBeDefined(); expect(utils.toLowerCase("HELLO WORLD")).toEqual("hello world"); });

        これは:

        describe(">String Utils", function() { it("should be able to lower case a string",function() { expect(utils.toLowerCase).toBeDefined(); expect(utils.toLowerCase("HELLO WORLD")).toEqual("hello world"); }); it("should be able to upper case a string",function() { expect(utils.toUpperCase).toBeDefined(); expect(utils.toUpperCase("hello world")).toEqual("HELLO WORLD"); }); it("should be able to confirm if a string contains a substring",function() { expect(utils.contains).toBeDefined(); expect(utils.contains("hello world","hello",0)).toBeTruthy(); }); it("should be able repeat a string multiple times",function() { expect(utils.repeat).toBeDefined(); expect(utils.repeat("hello", 3)).toEqual("hellohellohello"); }); });

        カスタムマッチャー

        Jasmineは、組み込みマッチャーでカバーされていないアサーションを実装するため、またはテストをより説明的で読みやすたとえば、次の仕様を考えてみましょう。

        it("should be able to tell if a number is even",function() { expect(utils.isEven).toBeDefined(); expect(utils.isEven(2)).toBeTruthy(); expect(utils.isEven(1)).toBeFalsy(); });

        isEven()メソッドが実装されていないとしましょう。 テストを実行すると、次のスクリーンショットのようなメッセージが表示されます:p>

        私たちが得る失敗メッセージは、私たちに何が起こっているのか見当もつかない定義されている それでは、このメッセージをコードドメインの文脈でより意味のあるものにしましょう(これは複雑なコードベースにとってより便利です)。 この問題については、カスタムマッチャーを作成してみましょう。

        マッチャーとして追加される1つまたは多くのプロパティで構成されるオブジェクトを取るaddMatchers()utilmatchersUtil.jscustomEqualityTestersutil.equalsmatchersUtil.jscustomEqualityTestersutil.equalscompare関数を持つオブジェクト。

        beforeEach()メソッドを使用して各仕様を実行する前に、カスタムマッチャーを登録する必要があります:

        describe("/Basic Math Utils", function () {beforeEach(function () {jasmine.addMatchers({hasEvenMethod: function (util, customEqualityTesters) {return {compare: function (actual, expected) {var result = { pass: utils.isEven !== undefined };if (result.pass) {result.message = "Expected isEven() to be not defined."}else {result.message = "Expected isEven() to be defined."}return result;}}}});});/*...*/});

        次に、expect(utils.isEven).toBeDefined():

        expect().hasEvenMethod();

        これは私たちによ

        beforeeach()とaftereach()を使用して

        仕様の初期化とクリーニングのために、jasmineは二つのグローバル関数を提供しますbeforeEach()afterEach():

        • beforeEach関数は、呼び出されるスイートの各仕様の前に1回呼び出されます。li>
        • afterEachdescribe()beforeEach()afterEach()関数を使用して各仕様の後に変数をリセットすることができるので、各仕様の初期化とクリーンアップコードを繰り返す

          beforeEach()addMatchers()done()関数など、多くのJasmine Apiと完全に結合されています。Jasmineで使用可能なグローバルfail()メソッドを使用して、テストを強制的に失敗させることができます。 たとえば、次のようにします。

          it("should explicitly fail", function () { fail('Forced to fail'); });

          次のエラーが発生するはずです:

          例外のテスト

          コードを単体テストすると、エラーや例外がスローされる可能性があるため、これらのシナリオをテストする必要があるかもしれません。 Jasmineは、例外がスローされたときのテストや特定の例外のテストを行うためのtoThrow()toThrowError()TypeError例外をスローする関数がある場合:あなたは例外がスローされた場合をテストする仕様を書くことができます:

          it('it should throw an exception', function () { expect(throwsError).toThrow(); });

          または、特定のTypeError例外:

          it('it should throw a TypeError', function () { expect(throwsError).toThrowError(TypeError); });

          スパイを理解する

          多くの場合、方法は他の方法に依存します。 これは、メソッドをテストするときに、その依存関係をテストすることになる可能性があることを意味します。 つまり、メソッドを分離し、一連の入力が与えられたときにどのように動作するかを確認することで、純粋な関数をテストする必要があります。

          Jasmineは、オブジェクトのメソッド呼び出しをスパイ/リッスンし、メソッドが呼び出されたかどうか、およびどのコンテキストと引数を報告するために使Jasmineは、メソッド呼び出しをスパイするための二つの方法を提供しています。spyOn()createSpy()jasmine.createSpy()を使用する必要があります。

          デフォルトでは、spyは、spied関数を呼び出さずに呼び出しが行われた場合にのみ報告します(i.p>

          • and.callThrough():元の関数を介して呼び出し、
          • and.returnValue(value):指定された値を返し、
          • and.callFake(fn):元の関数の代わりに偽の関数を呼び出します一つ、
          • and.throwError(err):エラーをスローし、
          • and.stub():デフォルトのスタブ動作をリセットします。たとえば、関数が何回呼び出されたかを知りたい場合など、spyを使用して、spied関数の実行時統計を収集できます。

            toUpperCase()String.toUpperCase()String.toUpperCase()String.toUpperCase():

            it("should be able to upper case a string", function () { 
            var spytoUpperCase = spyOn(String.prototype, 'toUpperCase') 
            expect(utils.toUpperCase).toBeDefined(); expect(utils.toUpperCase("hello world")).toEqual("HELLO WORLD"); expect(String.prototype.toUpperCase).toHaveBeenCalled(); expect(spytoUpperCase.calls.count()).toEqual(1); });

            この試験に失敗した台になると期待でutils.toUpperCase("hello world")toUpperCase()callThrough()を呼び出します:p>

            spy関数は、デフォルトでspied関数をスタブに置き換えます。 代わりに元の関数を呼び出す必要がある場合は、.and.callThrough()spy

            var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callThrough();

            今、すべての期待が合格します。また、and.callFake()and.returnValue()String.toUpperCase()utils.toUpperCase()実装を使用しないと、次の失敗が発生します。

            var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callFake(function(){ return "HELLO WORLD"; });

            String.toUpperCase()utils.toUpperCase()実装では、次の失敗が発生します。

            var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callFake(function(){ return "HELLO WORLD"; });

            二つの期待expect(String.prototype.toUpperCase).toHaveBeenCalled()expect(spytoUpperCase.calls.count()).toEqual(1)失敗しました。

            Jasmineの非同期性を処理する方法

            テストしているコードに非同期操作が含まれている場合は、非同期操作が完了したときにJasmineに知らせる方法が必

            デフォルトでは、Jasmineは、コールバック、promise、またはasyncキーワードで定義された非同期操作が終了するのを待ちます。 Jasmineが次の関数のいずれかでコールバック、promise、またはasyncキーワードを見つけた場合:beforeEachafterEachbeforeAllafterAllit次の操作に進む前に非同期が行われるようにします。beforeEach()/it()でdone()を使用します。.

            simulateAsyncOp()setTimeout()beforeEach()done()

            function simulateAsyncOp(callback){ 
            setTimeout(function () { callback(); }, 2000); }

            この関数をテストするために、beforeEach()done()を呼び出して、非同期操作が完了したことをJasmineに伝える必要があります:このメソッドの欠点にすぐに気づくことができるので、done()done()simulateAsyncOp(fn)done()。テストの記述方法に依存するコードを作成したくない場合は、代わりにpromiseを使用して、promiseが解決されたときにdone()コールバックを呼び または、Jasmine2.7以降では、コードがPromiseを返すと、Jasmineは次のコードを実行する前に解決または拒否されるまで待機します。Jasmine2.7+は、仕様でasyncawait.then().catch()simulateAsyncOp:

            function simulateAsyncOp() { 
            return new Promise(resolve => { setTimeout(() => { resolve(true); }, 1000); }); }

            Jasmine Clockの使用

            Jasmine clockは、setTimeout()などの時間関数に依存する非同期コードをテストするために使用されます。 このようにして、クロックを制御または手動で進めることによって、テストされた機能を同期的に実行できます。Jasmineクロックをインストールするには、仕様またはスイートでjasmine.clock().install関数を呼び出します。

            時計を使用した後、元の機能を復元するにはアンインストールする必要があります。

            Jasmine clockを使用すると、JavaScriptsetTimeoutsetIntervaljasmine.clock().tick関数を使用して時間を進めるためにクロッJasmineクロックを使用して、現在の日付をモックすることもできます。

            これは

            beforeEach(function () {jasmine.clock().install();});afterEach(function() {jasmine.clock().uninstall();});it("should call the asynchronous operation synchronously", function() {var completed = false;utils.simulateAsyncOp(function(){completed = true;});expect(completed).toEqual(false);jasmine.clock().tick(1001);expect(completed).toEqual(true);});

            これはsimulateAsyncOp関数です:p>

            function simulateAsyncOp(callback){ 
            setTimeout(function () { callback(); }, 1000); }

            mockDate

            エラーの処理

            何らかのエラーが原因で非同期コードが失敗した場合、仕様が正しく失敗するようにします。 Jasmine2.6以降では、未処理のエラーは現在実行されている仕様に送信されます。Jasmineは、明示的に仕様を失敗させる必要がある場合に使用できる方法も提供します。

            Jasmine:

            • done()beforeEach()done.fail(err)メソッドを呼び出すことにより、
            • 単にエラーをdone(err)コールバック(Jasmine3+)、
            • reject()Promiseのメソッドを呼び出します。このガイドでは、Jasmineを紹介し、jasmineを使用してJavaScriptコードを単体テストする方法を説明しました。 読んでくれてありがとう!

              この記事はもともとtechiediariesに掲載されました。

  • コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です