フロントエンドユニットテスト実装チュートリアルmocha+mochawesome+istanbul+sinon+chai


なぜユニットテストを書くのか
  • バグを減らす
  • コードの品質を向上させ、あなたのコードがテスト可能な
  • であることを保証します.
  • 安心再構築
  • すべての方法でユニットテストを書いた場合、変更ごとに対応するユニットテストに影響します.これにより、どこが影響するか、特に複雑なプロジェクトや非コア機能(テストされにくい)を考えなくても、バグが発生します.
    コードがテストできない場合は、コードを再構築する必要があるかどうかを考慮する必要があります.良いコードは、職責が明確で単一であり、粒子度が小さく、テストが容易であるべきである.
    再構築するとき、特に広い範囲の再構築では、勇気と自信があります.
    ユニットテストにはどのような要素が必要ですか?
  • 試験フレーム
  • テストレポート
  • 試験カバー率
  • 断言
  • mock

  • テストフレームワークmocha公式ドキュメントの選択
    インストール
    npm install mocha

    package.json
    "scripts": {
            "test": "mocha --recursive --require babel-core/register tests/Js/test"
        }

    mochaのデフォルトでは、プロジェクトのルートディレクトリの下にあるtestディレクトリが見つかりますが、多くの人がプロジェクトディレクトリのセルテストディレクトリはtestではなく、/tests/Js/testでscriptsにセルテストパスを追加すると、デフォルトアドレスを変更できます.
    recursiveパラメータは、ディレクトリを検索するすべてのサブディレクトリのセルテストを表します.そうしないと、現在のディレクトリのセルテストのみが検索されます.
    Nodeではes 6構文はサポートされていません.babelでコンパイルする必要があります.そのため、--require babel-core/registerを追加する必要があります.
    プロジェクトのルートディレクトリに追加する必要があります.babelrcファイル
    {
      "presets": [ "es2015" ]
    }

    tests/Js/testディレクトリの下にファイルtestを作成します.js
    var assert = require('assert');
    describe('Array', function() {
      describe('#indexOf()', function() {
        it('should return -1 when the value is not present', function() {
          assert.equal([1,2,3].indexOf(4), -1);
        });
      });
    });

    コマンドラインでnpm run testを実行した結果は次の通りです.
    以上,フロントエンドテストフレームワーク,es 6構文問題,実行経路問題の導入方法について述べた.
    コマンドラインの結果が不明になった場合、テストレポートを出力したい場合はmochawesomeでインストールできます
    npm install --save-dev mochawesome

    package.json
    "scripts": {
            "test": "mocha --recursive --reporter mochawesome --require babel-core/register tests/Js/test"
        }

    scriptsコマンドで、--reporter mochawesome実行コマンドを追加します.
    npm run test

    その結果、図のようにhtmlファイルとjsonファイルが生成されます.
    「コードオーバーライド率」(code coverage).測定次元は4つあります.
  • 行オーバーライド率(line coverage):各行が
  • を実行するかどうか
  • 関数オーバーライド率(function coverage):各関数が
  • を呼び出すかどうか
  • ブランチカバー率(branch coverage):ifコードブロックごとに
  • が実行するかどうか
  • 文オーバーライド率(statement coverage):各文が
  • を実行しているかどうか
    では、jsごとのカバー率をどのように知るかは、istanbulとbabel-istanbulのインストールに使用されます.
    npm install istanbul
    npm install babel-istanbul

    package.json
    "scripts": {
         "test:cover": "babel-node ./node_modules/.bin/babel-istanbul cover _mocha -- tests/Js/* -R spec --recursive
        }

    istanbul彼もいくつかのes 6文法をサポートしていないので、babel変換はcoverパラメータを使用してmochaを結合する必要があります.--後のパラメータがmochaに渡されることを表します.
    コマンドの実行
    npm run test:cover

    結果は図のように


    Mocha自体はアサーションライブラリを持たないので,まずアサーションライブラリを導入しなければならない.ここではchaiを使います
    npm install chai

    chaijsには3つの断言スタイルがあり、詳細は公式サイトを参照してください.
    jqueryは大部分が使用するライブラリとして、このようなコードをどのようにユニットテストするか、例えば以下のコードhide-element.js
    export const hideElement = ($element) => {
      $element.on('click', '.hide', function() {
        $(this).hide();
      });
    };

    まずnode環境とブラウザ環境は異なるので、このようなユニットテストを実行するにはブラウザ環境をシミュレートする必要があります.jsdomをインストールする必要があります.
    npm install jsdom

    test.jsは以下の通り
    const assert = require('chai').assert;
    const { hideElement } = require('xxxx/hide-element.js');
    describe('test:hide-element.js', function(done) {
      before(function() {
        let { JSDOM } = require('jsdom');
        let dom = new JSDOM(`
    `,{ url: 'http://127.0.0.1/', referrer: 'http://127.0.0.1/', contentType: 'text/html', userAgent: 'Mellblomenator/9000', includeNodeLocations: true, }); global.window = dom.window; global.$ = require('jquery'); hideElement($('body')); }); it('click event', function() { $('body').find('.hide').trigger('click'); assert.equal($('.hide').css('display'), 'none'); }); });
    1. mocha 由 describe,it基本元素组成
    2. mocha 有四个钩子函数 before,after,beforeEach,afterEach
    3. 因为node中引入依赖时会缓存模块,初始化jsdom环境时,最好在before中,防止污染jsdom环境,导致不同的单元测试之间互相影响

    需要测试的代码中依赖了其他的模块时,为了测试需要测试的代码,而不去关心依赖的模块,这时候我们需要 sinon 去mock掉相关依赖

    demo.js

    
    import api from 'api';
    export const demo = (arg) => {
        if (arg == 1) {
          return api.get({
            params: params
          });
        }
        
        return 'ok';
    };

    test.js
    import { demo } from 'xx/demo.js';
    const assert = require('chai').assert;
    const sinon = require('sinon');
    import api from 'api';
    
    describe('demo', function() {
      it('demo(1)', function() {
        //mock api get  ,         'N'
        let apiGet = sinon.stub(api, 'get').returns('N');
        let expectedParams = {params: 'yes'};
        let res = demo(1);
        //automate clean-up,          
        apiGet.restore();
        //    api.get         {params: 'yes'}
        sinon.assert.calledWith(apiGet, expectedParams);
        
        assert.equal(res, 'N');
      });
    });