はしくれエンジニアもどきのメモ

情報系技術・哲学・デザインなどの勉強メモ・備忘録です。

JSのユニットテストフレームワークJasmine 3系メモ

JSのユニットテストフレームワークJasmine 3系メモ

CodeprepさんJavaScriptのコードレベルBDD向けのユニットテストフレームワークJasmineの紹介があったので,v3系の使い方メモ. (基本的にはv2系と変わらない)

環境

  • Windows10

TDD/BDDについて

テスト駆動開発(TDD)とは

 TDDとはテストファーストによる追加・変更と、リファクタリングによる設計改善の2つの活動を超短期で繰り返して開発を進めていく手法です。この手順は「RED」(テストを失敗させた状態)、「GREEN」(テストを成功させた状態)、「REFACTOR」(リファクタリングをしている段階)の3ステップを高速に回すサイクルで表現されます。

「振る舞い駆動開発」とは、TDDに触発されてDan North氏により提唱され発展した手法です。

BDDはTDDの一流派ともいえますが、TDDに対し以下の実現のための原則や工夫が加えられています。

  • テストを「振る舞い」(機能的な外部仕様)の記述に特化させる
  • ユーザーの要求やアーキテクチャの設計仕様といった、より上位のインプットとTDDのテストにつながりを持たせる

一例として、前述のアウトサイドインTDDもBDDの一種に該当します。なおBDDはTDDから生まれた手法ではあるものの、TDDで欠落しがちになったアジャイルテストファーストの目的・原則に立ち返るという、原点回帰の方向性も備えています。

TDD/BDDの理論に関する(歴史含めた)日本語資料: テスト駆動開発/振る舞い駆動開発を始めるための基礎知識 (1/3):いまさら聞けないTDD/BDD超入門(1) - @IT

BDDの出典的資料(英語):Introducing BDD | Dan North & Associates

コードレベルのBDD

コードレベルのBDDは、「ユニットテスト」(単体テスト)や、コードレベルの結合テストといったテストレベルを扱う、プログラミングを駆動するためのBDDです。

テスト駆動開発/振る舞い駆動開発を始めるための基礎知識 (3/3):いまさら聞けないTDD/BDD超入門(1) - @IT

ユニットテストフレームワーク「Jasmine」もユニットテストを扱うのでコードレベルBDDに該当する.

記述方法としてdescribe, itを使うことが多い.

例:

describe("テストスイート名", function() {
  it("テスト1", function() {
    // 評価式
  });
  it("テスト2", function() {
    // 評価式
  });
  ...
});

ユーザレベルのBDD

ユーザーレベルのBDDは、受け入れテストやEnd-To-Endのシステムテストといったテストレベルを扱う、ユーザー要求や外部仕様の実現を駆動するBDDです。

  • ユーザー要求や外部仕様を、自動化された受け入れテストやシステムテストで記述する。テストの記述には、自然言語のようにテストを書けるセミフォーマルな言語や、ユーザーが可読できるドメイン特化言語(Domain-Specific Language、DSL)がよく用いられる
  • アジャイル開発における「イテレーション」などの大きな単位で、テスト失敗→テスト成功のテストサイクルを回していく(テストサイクルを数十秒から数十分で回すプログラミング手法としてのTDDとは異なるスタイルを採る)

テスト駆動開発/振る舞い駆動開発を始めるための基礎知識 (3/3):いまさら聞けないTDD/BDD超入門(1) - @IT

対になるのはエンドツーエンド(E2E)テスト(ユーザーテスト)が該当する,有名ドコロのフレームワークは以下がある.

  • Cucumber
  • Selenium(WebDriver使う系,ブラウザの自動操作ライブラリに近い)
  • TestCafe(どちらかというとテストランナー)

記述方法として,Given A, When B, Then C を使うものが多く, 状態遷移マシンと合わせて「事前状態Aのとき,Bというアクション時,Cという結果になる」といった表現になる.

例:

Feature: ウェブページの表示と遷移テスト
  Google検索でウェブページの表示と遷移を確認します
  Scenario: Searching for test
    Given "https://www.google.com/"を開く
    When "test"を入力してボタンをクリックする
    Then "test - Google Search"というタイトルページが表示されること

JavaScriptユニットテストフレームワーク

Jasmineの特徴:

  • スタンドアローン系のフレームワークでこれ1つで簡単に動作可能(それゆえ拡張性に欠ける).
  • CDNを利用でき,ブラウザでテスト結果を出力・確認できる(テストコードもブラウザで動くようにする必要があるが).
  • 時間処理(時間指定でsetIntervalやsetTimeoutの前後の確認可能)対応
  • 非同期処理対応
  • モック対応
  • 2014年頃は開発が盛んだったが最近は下火(Githubでの更新が少ない)

有名ドコロの他のユニットテストフレームワークは以下がある.

他には以下の記事(2017年)で解説されている.

postd.cc

Wikipediaにもまとめられている(少し古いが).

ja.wikipedia.org

JasmineをCDNで導入(ブラウザ上でテストの実行・確認)

Node.jsなどを利用した基本的な導入方法はGetStartedのページにある.

Getting Started

ただし,CDNで気軽に使うこともでき,その場合は以下の4ファイルを読み込めばいい.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.3.0/jasmine.min.css">

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.3.0/jasmine.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.3.0/jasmine-html.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.3.0/boot.min.js"></script>

なお,JSファイルには順番があるので注意.boot.jsは最後に読み込む.

Node.jsなどで導入した場合もパスを調整すればブラウザで確認できる.

<link rel="shortcut icon" type="image/png" href="jasmine/lib/jasmine-{#.#.#}/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-{#.#.#}/jasmine.css">

<script type="text/javascript" src="jasmine/lib/jasmine-{#.#.#}/jasmine.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-{#.#.#}/jasmine-html.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-{#.#.#}/boot.js"></script>

テスト用スクリプトやファイルは,最後に読み込む.

Jasmineの構文

CDNが利用できるので, CodepenにCodeprepさんの内容を参考に使いそうな構文をまとめた.

See the Pen jasmineSample by Cartman (@Cartman0) on CodePen.

toBe と toEqualの違い

  • toBe(): 厳密比較 ===に該当
  • toEqual(): ==に該当

オブジェクトの比較の際,同じプロパティを持っているかであればtoEqual()を使用し, 厳密に同じオブジェクトであるかであればtoBe()を使用する.

describe("テストスイート名", function() {
  it("object A, Bが等しいか", function() {
    var A = {
      name: "sato",
    };
    var B = {
      name: "sato",
    };
    expect(A).toBe(B); // fail
    // expect(A).toBe(A); // success
  });
  it("object A, Bが等しいか", function() {
    var A = {
      name: "sato",
    };
    var B = {
      name: "sato",
    };
    expect(A).toEqual(B); // success
  });
});

他の機能は随時追加予定