単体テスト

コードを変更または追加したら、既存の単体テストを実施して、 詳しく書いてくださいすべてのテストは、圧縮されていないバージョンのコードに対して実行されます。

単体テストには、JS テストとブロック生成ツールのテストがあります。

JS テスト

JS テストは、Blockly のコアでの内部 JavaScript 関数の動作を確認します。Mocha を使用して単体テストを実行し、Sinon を使用して依存関係をスタブし、Chai を使用してコードに関するアサーションを行います。

テストの実行

ブロックサンプルとブロックサンプルの両方で、npm run test によって単体テストが実行されます。Blockly では、リンティングやコンパイルなどの他のテストも実行されます。Google Chat では ブラウザで tests/mocha/index.html を開き、すべての mocha をインタラクティブに実行することもできます。 テストです。

テストの作成

テストの実行には Mocha TDD インターフェースを使用します。テストはスイートに編成されます。スイートには、追加のサブスイートやテストの両方を含めることができます。通常、Blockly の各コンポーネント(toolboxworkspace など)には、1 つ以上のスイートを含む独自のテストファイルがあります。スイートごとに setupteardown を指定できます。 各テストの前後に呼び出されるメソッドを 説明します。

テストヘルパー

Blockly には、テストの作成時に役立つ Blockly 固有のヘルパー関数がいくつかあります。これらは coreblockly-samples にあります。

ヘルパー関数には sharedTestSetupsharedTestTeardown があります。 テストの前後に呼び出す必要がある(要件を参照)。 セクションを参照)。

sharedTestSetup:
  • sinon の偽のタイマーを設定します(一部のテストでは this.clock.runAll を使用する必要があります)。
  • Blockly.Events.fire を直ちに起動するようにスタブします(構成可能)。
  • defineBlocksWithJsonArray で定義された blockType の自動クリーンアップを設定します。
  • this コンテキストでいくつかのプロパティを宣言します。 アクセスしやすい:
    • this.clock(ただし、復元しないでください。復元すると sharedTestTeardown で問題が発生します)
    • this.eventsFireStub
    • this.sharedCleanupaddMessageToCleanup および addBlockTypeToCleanup)(注: 「addBlockTypeToCleanup」を使用してブロックを定義した場合 defineBlocksWithJsonArray)

この関数には、設定を構成する省略可能な options パラメータが 1 つあります。現在、 Blockly.Events.fire をスタブして起動するかどうかを決定するためにのみ使用されます。 (デフォルトでスタブされます)。

sharedTestTeardown:
  • ワークスペース this.workspace の破棄(定義された場所に応じて、 詳細については、テスト要件のセクションをご覧ください)。
  • すべてのスタブを復元します。
  • defineBlocksWithJsonArray を通じて追加されたすべてのブロックタイプをクリーンアップし、 addBlockTypeToCleanup
  • addMessageToCleanup で追加されたすべてのメッセージをクリーンアップします。

テストの要件

  • 各テストは、最も外側のスイートのセットアップの最初の行として sharedTestSetup.call(this); を呼び出し、ファイルの最も外側のスイートのテイクダウンの最後の行として sharedTestTeardown.call(this); を呼び出す必要があります。
  • 汎用のツールボックスを備えたワークスペースが必要な場合は、 プリセット ツールボックス テスト index.html。以下に例を示します。
  • this.workspace は適切に廃棄する必要があります。ほとんどのテストでは、 最も外側のスイートで this.workspace を定義し、それを後続のすべてのスイートに使用 内部スイートで定義または再定義する場合もあります。 (たとえば、いずれかのテストで、異なるオプションを持つワークスペースが必要) できます)。テスト終了時に廃棄する必要があります。
    • 最も外側のスイートで this.workspace を定義し、再定義しない場合は、それ以上の操作は必要ありません。sharedTestTeardown によって自動的に破棄されます。
    • this.workspace を内部スイートで初めて定義する場合(つまり、最も外側のスイートで定義しなかった場合)、そのスイートのテイクダウンで workspaceTeardown.call(this, this.workspace) を呼び出して、手動で破棄する必要があります。
    • 最も外側のスイートで this.workpace を定義した後、再定義する場合 作成するには、まず呼び出しを行う必要があります。 workspaceTeardown.call(this, this.workspace) 再定義する前 最上位のスイートで定義されている元のワークスペースを破棄します。マイページ 新しい値を手動で破棄する必要もあります。 workspaceTeardown.call(this, this.workspace): の破棄で再び 利用できます

テストの構成

単体テストは通常、一定の構造に従います。これは、次のように要約できます。

  1. Arrange: 世界の状態と、 変更することはできません。
  2. Act: テスト対象のコードを呼び出して、テスト対象の動作をトリガーします。
  3. アサート: 戻り値またはモックされたオブジェクトとのやり取りについてアサートを行い、正確性を確認します。

単純なテストでは、設定する動作がない場合があります。その場合は、テスト対象のコードへの呼び出しをアサーションにインライン化することで、実行ステージとアサート ステージを組み合わせることができます。より複雑なケースでは、これらの 3 つのステージに沿ってテストを作成すると、テストの読みやすさが向上します。

テストファイルの例を次に示します(実際のファイルから簡素化しています)。

suite('Flyout', function() {
  setup(function() {
    sharedTestSetup.call(this);
    this.toolboxXml = document.getElementById('toolbox-simple');
    this.workspace = Blockly.inject('blocklyDiv',
        {
          toolbox: this.toolboxXml
        });
  });

  teardown(function() {
    sharedTestTeardown.call(this);
  });

  suite('simple flyout', function() {
    setup(function() {
      this.flyout = this.workspace.getFlyout();
    });
    test('y is always 0', function() {
      // Act and assert stages combined for simple test case
      chai.assert.equal(this.flyout.getY(), 0, 'y coordinate in vertical flyout is 0');
    });
    test('x is right of workspace if flyout at right', function() {
      // Arrange
      sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
        viewWidth: 100,
      });
      this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_RIGHT;
      this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_RIGHT;

      // Act
      var x = this.flyout.getX();

      // Assert
      chai.assert.equal(x, 100, 'x is right of workspace');
    });
  });
});

この例で注意すべき点は次のとおりです。

  • スイートには、追加の setup メソッドと teardown メソッドを持つ他のスイートを含めることができます。
  • 各スイートとテストにはわかりやすい名前が付いています。
  • Chai アサーションは、コードに関するアサーションを作成するために使用されます。
    • 文字列引数を任意で指定することもできます。この引数は、リクエストが テストが失敗します。これにより、破損したテストのデバッグが容易になります。
    • パラメータの順序は chai.assert.equal(actualValue, expectedValue, optionalMessage) です。actualexpected を入れ替えると、エラー メッセージが意味不明になります。
  • Sinon は、実際のコードを呼び出さない場合にメソッドのスタブに使用されます。この例では、実際の指標関数を呼び出す必要はありません。このテストには関連性がないためです。結果がどのように使用されるか 渡します。Sinon は getMetrics 関数をスタブして、テストの断言で簡単に確認できる返信を返します。
  • 各スイートの setup メソッドには、すべてのテストに適用される一般的な設定のみを含める必要があります。特定の動作のテストが特定の条件に依存している場合は、その条件を関連するテストで明確に述べておく必要があります。

テストのデバッグ

  • ブラウザでテストを開き、デベロッパー ツールを使用してブレークポイントを設定し、テストが予期せず失敗している(または予期せず成功している)かどうかを調査できます。
  • テストまたはスイートで、そのテストセットのみを実行するように .only() または .skip() を設定する。 テストをスキップできます例:

    suite.only('Workspace', function () {
      suite('updateToolbox', function () {
        test('test name', function () {
          // ...
        });
        test.skip('test I don’t care about', function () {
          // ...
        });
      });
    });
    

    コードを commit する前に、これらのコメントを削除してください。

ブロック生成ツールのテスト

各ブロックには独自の単体テストがあります。これらのテストでは、ブロックが コードが意図したとおりに機能しない場合があります。

  1. Firefox または Safari で tests/generators/index.html を読み込みます。なお、Chrome と Opera は セキュリティ制限により、ローカルの「file://」からテストを読み込めない (問題 4102447416)。
  2. テストするシステムの該当部分をプルダウン メニューから選択します。 [Load]をクリックしますワークスペースにブロックが表示されます。
  3. [JavaScript] をクリックします。
    生成されたコードをコピーして、JavaScript コンソールで実行します。出力が終了した場合 テストは合格です。
  4. [Python] をクリックします。
    生成されたコードをコピーして、Python インタープリタで実行します。出力が「OK」で終わっている場合は、テストに合格しています。
  5. [PHP] をクリックします。
    生成されたコードをコピーして、PHP インタープリタで実行します。出力が「OK」で終了している場合、テストは合格です。
  6. [Lua] をクリックします。
    生成されたコードをコピーして、Lua インタープリタで実行します。 出力が「OK」で終了している場合、テストは合格です。
  7. [Dart] をクリックします。
    生成されたコードをコピーして、Dart インタープリタで実行します。 出力が「OK」で終了している場合、テストは合格です。

ブロック ジェネレータ テストの編集

  1. ブラウザで tests/generators/index.html を読み込みます。
  2. プルダウン メニューからシステムの該当する部分を選択し、[ 「読み込み」。ワークスペースにブロックが表示されます。
  3. ブロックに変更や追加を行います。
  4. [XML] をクリックします。
  5. 生成された XML を tests/generators/ の適切なファイルにコピーします。