フロントエンド Vue ユニットテストを始める

フロントエンド Vue ユニットテストを始める

1. ユニットテストはなぜ必要なのでしょうか?

ユニット テストは、関数、クラス、コンポーネントなど、プロジェクト内のモジュールの機能をテストするために使用されます。ユニットテストの機能は次のとおりです。

  • 正確性: コードの正確性を確認し、オンラインになる前に詳細な準備を行うことができます。
  • 自動化: テスト ケースをコード バージョン管理に統合して、ユニット テストを自動的に実行し、毎回の手動操作を回避できます。
  • 説明: テスト対象モジュールのドキュメントへの参照を他の開発者に提供できます。テスト ケースを読むと、ドキュメントを読むよりも完全な場合があります。
  • 開発を推進し、設計をガイドする: 事前に作成されたユニット テストは、開発の API 設計をガイドし、設計上の問題を事前に検出することもできます。
  • リファクタリングを確実に行う: テスト ケースを複数回検証できるため、回帰テストが必要な場合に多くの時間を節約できます。

2. ユニットテストの書き方

テストの原則

  • コードをテストするときは、内部実装ではなく、テストのみを考慮してください。
  • データは可能な限り現実をシミュレートする必要があり、現実に近いほど良い
  • データの境界条件を十分に考慮する
  • 主要コード、複雑コード、コアコードのテストに重点を置く
  • テストと機能開発を組み合わせると、設計とコードのリファクタリングに役立ちます。

書き方の手順

  • 準備段階: パラメータの構築、スパイの作成など
  • 実行フェーズ: 構築されたパラメータを使用してテストされたコードを実行する
  • アサート段階:実際の結果と予想される結果を比較して、テストが正常かどうかを判断します。
  • クリーンアップフェーズ: 準備フェーズによる外部環境への影響をクリーンアップし、準備フェーズで作成されたスパイを削除するなどします。

3. テストツール

ユニット テスト ツールは、次の 3 つのカテゴリに分けられます。

  • テストランナー: さまざまなブラウザ環境をシミュレートし、Karma などのテスト フレームワークとアサーション ライブラリをカスタマイズできます。
  • テスト フレームワーク: ユニット テスト用の機能モジュールを提供します。一般的なフレームワークには、Jest、mocha、Jasmine、QUnit などがあります。
  • ツール ライブラリ: assert、should.js、expect.js、chai.js、enzyme レンダリング ライブラリ、Istanbul カバレッジ計算などのアサーション ライブラリ。

ここでは、Jest を例として使用します。 Jest は包括的で、さまざまなツールを統合しており、設定が簡単で、設定なしで直接使用することもできます。

4. Jest を使い始める

Jestの公式サイトでの説明は次のとおりです。

Jest はシンプルさを重視した、優れた JavaScript テスト フレームワークです。

インストール

糸を追加 --dev ジェスト
# または
# npm インストール -D ジェスト

簡単な例

公式ウェブサイトで提供されている例から始めて、2 つの数値を加算する関数をテストし、sum.js ファイルを作成します。

関数 sum(a, b) {
  a + b を返します。
}
モジュールのエクスポートの合計。

次に、sum.test.js ファイルを作成します。

const sum = require('./sum');

test('1 + 2 を足すと 3 になる', () => {
  期待値(合計(1, 2))toBe(3);
});

package.json にテスト タスクを追加します。
{
  「スクリプト」: {
    「テスト」: 「冗談」
  }
}

最後に、 yarn test または npm run test を実行すると、Jest は次のメッセージを出力します。

合格 ./sum.test.js
✓ 1 + 2 を加算して 3 にする (5ms)

この時点で、基本的な単体テストは完了です。

注: Jest は JSDOM を使用して、Node 仮想ブラウザ環境で実際のブラウザをシミュレートします。DOM は js でシミュレートされるため、Jest はスタイルをテストできません。 Jest テスト ランナーは JSDOM を自動的にセットアップします。

ジェストクリ

コマンドラインから Jest を直接実行し (jest がすでに PATH 内にあると想定、たとえば yarn global add jest または npm install jest --global 経由)、さまざまな便利な構成オプションを指定できます。のように:

jest my-test --notify --config=config.json

Jest コマンドには次の共通パラメータがあります。

  • --coverage はユニットテストのカバレッジを出力することを意味します。カバレッジ ファイルは、デフォルトでは tests/unit/coverage/lcov-report/index.html にあります。
  • --watch 監視モードでは、テスト ケースに関連するファイルに変更が加えられると、ユニット テストが再トリガーされます。

その他のオプションについては、Jest CLI オプションを参照してください。

設定ファイルの使用

jest コマンドを使用して設定ファイルを生成します。

ジェスト --init

いくつかのオプションから選択できます:

√ 設定ファイルに Typescript を使用しますか? ... いいえ
√ テストに使用するテスト環境を選択します » jsdom (ブラウザライク)
√ Jest でカバレッジレポートを追加しますか? ... はい
√ カバレッジのためにコードをインストルメントするにはどのプロバイダーを使用すべきですか? » babel
√ テストごとにモック呼び出しとインスタンスを自動的にクリアしますか? ... はい

設定ファイルの例 (上記の選択に基づかない):

// jest.config.js
定数パス = require('path')

モジュール.エクスポート = {
    プリセット: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
    ルートディレクトリ: path.resolve(__dirname, './'),
    カバレッジディレクトリ: '<rootDir>/tests/unit/coverage',
    収集範囲: [
        'src/*.{js,ts,vue}',
        'src/directives/*.{js,ts,vue}',
        'src/filters/*.{js,ts,vue}',
        'src/helper/*.{js,ts,vue}',
        'src/views/**/*.{js,ts,vue}',
        'src/services/*.{js,ts,vue}'
    ]
}

Babelの使用

yarn を追加 --dev babel-jest @babel/core @babel/preset-env

プロジェクトのルート ディレクトリに babel.config.js ファイルを作成して、現在の Node バージョンと互換性のある Babel を設定できます。

// babel.config.js
モジュール.エクスポート = {
  プリセット: [['@babel/preset-env', {targets: {node: 'current'}}]],
};

vue-cli で Jest を使用する

vue-cli で Jest を使用するには、プロジェクトに @vue/cli-plugin-unit-jest プラグインをインストールします。

vue ユニットを追加-jest
# または
# yarn add -D @vue/cli-plugin-unit-jest @types/jest
「スクリプト」: {
    "テスト:ユニット": "vue-cli-service テスト:ユニット --coverage"
},

@vue/cli-plugin-unit-jest は、vue-cli-service に test:unit コマンドを挿入し、デフォルトで次のファイルを認識します: <rootDir>/(tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)) は、ユニットテスト (tests/unit ディレクトリ内の .spec.(js|jsx|ts|tsx) で終わるファイルと、__tests__ という名前のディレクトリ内のすべての js(x)/ts(x) ファイル) を実行します。

一般的な例

値が等しいと判断する

toBe() は、2 つのプリミティブ型が完全に一致するかどうかをチェックします。

test('2 + 2 は 4', () => {
  期待値(2 + 2)が4になる;
});

toEqual() はオブジェクトが等しいかどうかをチェックします:

test('オブジェクトの割り当て', () => {
  定数データ = {1:1};
  データ['2'] = 2;
  データ.toEqual({1: 1、2: 2}) を期待します。
});

誤った値をチェックする

  • toBeNullはnullのみに一致します
  • toBeUndefined は undefined のみに一致します
  • toBeDefinedはtoBeUndefinedの反対です
  • toBeTruthyは、真となるif文に一致します。
  • toBeFalsyは偽であるif文に一致する

例:

テスト('null', () => {
  定数 n = null;
  (n).toBeNull() を期待します。
  期待(n).toBeDefined();
  (n) が未定義でないことを予想します。
  期待(n)。真実ではない();
  期待値nは偽です。
});

テスト('ゼロ', () => {
  定数z = 0;
  (z) が Null でないことを予想します。
  期待(z).toBeDefined();
  期待(z).not.toBeUndefined();
  期待(z).not.toBeTruthy();
  期待値(z).toBeFalsy();
});

数字の比較

test('2プラス2', () => {
  定数値 = 2 + 2;
  期待値(値)が3より大きい場合;
  期待値。3.5より大きいか等しい。
  期待値。toBeLessThan(5);
  期待値。4.5未満です。

  // toBe と toEqual は数値の場合同等です
  期待値(値)が4である。
  期待値.toEqual(4);
});

浮動小数点数の等価性を比較する場合は、小さな丸め誤差に依存したテストを行わないようにするため、toEqual ではなく toBeCloseTo を使用します。

test('2つの浮動小数点数を加算する', () => {
  定数値 = 0.1 + 0.2;
  //expect(value).toBe(0.3); 浮動小数点数には丸め誤差があるため、エラーが発生します。expect(value).toBeCloseTo(0.3); // これは機能します });

文字列の比較

正規表現を使用して次のことを確認できます:

test('チームにはIは存在しません', () => {
  'team' が /I/ と一致しないことを予想します。
});

test('しかし、Christoph には「stop」があります', () => {
  'Christoph' が期待される。toMatch(/stop/);
});

配列と配列のような

toContain を使用すると、配列または反復可能オブジェクトに特定の項目が含まれているかどうかを確認できます。

const ショッピングリスト = [
  「おむつ」、
  「クリネックス」、
  「ゴミ袋」
  「ペーパータオル」
  '牛乳'、
];

test('買い物リストに牛乳が載っている', () => {
  expect(shoppingList).toContain('ミルク');
  新しい Set(shoppingList) を期待します。toContain('ミルク');
});

異常な

関数が例外をスローするかどうかを確認するためにも使用できます。

関数compileAndroidCode() {
  throw new Error('間違った JDK を使用しています');
}

test('Android のコンパイルは期待どおりに実行されます', () => {
  期待します(() => compileAndroidCode()).toThrow();
  期待します(() => compileAndroidCode()).toThrow(Error);

  // 正確なエラーメッセージや正規表現を使用することもできます
  expect(() => compileAndroidCode()).toThrow('間違った JDK を使用しています');
  期待します(() => compileAndroidCode()).toThrow(/JDK/);
});

詳細な使用方法については、API ドキュメントを参照してください。

現在のテストのみを実行する

only() メソッドを使用すると、このテストのみが実行されることを示すことができ、不要な繰り返しテストを減らすことができます。

test.only('雨が降っています', () => {
  予想(inchesOfRain()).toBeGreaterThan(0);
});

test('雪は降っていません', () => {
  期待値(inchesOfSnow())は0です。
});

非同期コードのテスト

コールバック関数

たとえば、データを取得し、完了したら callback(data) を呼び出す fetchData(callback) 関数があるとします。 返されるデータは文字列「ピーナッツバター」になるはずです。

test('データはピーナッツバターです', done => {
  関数コールバック(データ) {
    試す {
      expect(data).toBe('ピーナッツバター');
      終わり();
    } キャッチ(エラー){
      完了(エラー);
    }
  }

  fetchData(コールバック);
});

Done() は、テストの完了をマークするために使用されます。done() がないと、コールバックが呼び出されず、ユニット テストが完了していないため、ユニット テストはテストの完了後に終了しますが、これは期待どおりではありません。 done() 関数が呼び出されない場合は、タイムアウト エラーが報告されます。

expect の実行に失敗した場合はエラーがスローされ、後続の done() は実行されません。 テスト ケースが失敗した理由を知りたい場合は、try に expect を配置し、catch の done 関数にエラーを渡す必要があります。 そうしないと、コンソールにタイムアウト エラーが表示され、expect(data) で受信した値が表示されなくなります。

約束

上記の例を引き続き使用します。

test('データはピーナッツバターです', () => {
  fetchData() を返します。その後、data => {
    expect(data).toBe('ピーナッツバター');
  });
});

テストと関数が同時に完了するように、結果を返すことを忘れないでください。
Promise が拒否されることが予想される場合は、catch メソッドを使用します。

test('フェッチはエラーで失敗しました', () => {
  期待アサーション(1);
  fetchData() を返します。catch(e => expect(e).toMatch('error'));
});

解決マッチャーと拒否マッチャーを使用することもできます。

test('データはピーナッツバターです', () => {
  expect(fetchData()).resolves.toBe('ピーナッツバター'); を返します。
});

test('フェッチはエラーで失敗しました', () => {
  expect(fetchData()).rejects.toMatch('error'); を返します。
});

非同期/待機

test('データはピーナッツバターです', async () => {
  const データ = fetchData() を待機します。
  expect(data).toBe('ピーナッツバター');
});

test('フェッチはエラーで失敗しました', async () => {
  期待アサーション(1);
  試す {
    fetchData() を待機します。
  } キャッチ (e) {
    期待(e).toMatch('error');
  }
});

async/await は、resolves()/rejects() と組み合わせて使用​​することもできます。

test('データはピーナッツバターです', async () => {
  待機 expect(fetchData()).resolves.toBe('ピーナッツバター');
});

test('フェッチはエラーで失敗しました', async () => {
  期待(fetchData()).rejects.toMatch('error');を待機します。
});

取り付けと取り外し

テスト前とテスト後

場合によっては、テストを開始する前に何らかの準備を行い、テストが完了した後に何らかのクリーンアップを行う必要があります。beforeEach と afterEach を使用できます。
たとえば、各テストの前にいくつかの都市データを初期化し、テスト後にクリーンアップする必要があります。

それぞれの前に(() => {
  CityDatabase を初期化します。
});

afterEach(() => {
  CityDatabase をクリアします。
});

test('都市データベースにはウィーンがあります', () => {
  expect(isCity('ウィーン')).toBeTruthy();
});

test('都市データベースにサンファンが含まれています', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

同様のメソッドには beforeAll と afterAll があり、これらは現在の仕様テスト ファイルの開始前と終了前に 1 回ずつ実行されます。

テストケースのグループ化

デフォルトでは、before ブロックと after ブロックはファイル内のすべてのテストに適用されます。 さらに、describe ブロックを使用してテストをグループ化することもできます。 before ブロックと after ブロックが describe ブロック内にある場合、それらはその describe ブロック内のテストにのみ適用されます。

// このファイル内のすべてのテストに適用されます
それぞれの前に(() => {
  初期化CityDatabase() を返します。
});

test('都市データベースにはウィーンがあります', () => {
  expect(isCity('ウィーン')).toBeTruthy();
});

test('都市データベースにサンファンが含まれています', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

describe('都市と食べ物のマッチング', () => {
  // この記述ブロック内のテストにのみ適用されます
  それぞれの前に(() => {
    戻り値はinitializeFoodDatabase()です。
  });

  test('ウィーン<3ソーセージ', () => {
    expect(isValidCityFoodPair('ウィーン', 'ウィーナー・ヴュルスト')).toBe(true);
  });

  test('サンファン <3 プランテーン', () => {
    expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
  });
});

実行命令

describe はグループ化に使用されるため、ネストされたスコープが存在します。各ライフサイクルの実行順序は次のとおりです。

  • 外側のスコープの before は内側のスコープの前に実行され、 after はその逆になります。
  • 同じレベルでは、beforeAll は beforeEach の前に実行され、after はその逆になります。
beforeAll(() => console.log('1 - beforeAll'));
afterAll(() => console.log('1 - afterAll'));
beforeEach(() => console.log('1 - beforeEach'));
afterEach(() => console.log('1 - afterEach'));
テスト('', () => console.log('1 - テスト'));
describe('スコープ付き/ネストされたブロック', () => {
  beforeAll(() => console.log('2 - beforeAll'));
  afterAll(() => console.log('2 - afterAll'));
  beforeEach(() => console.log('2 - beforeEach'));
  afterEach(() => console.log('2 - afterEach'));
  テスト('', () => console.log('2 - テスト'));
});

// 1 - すべて前
// 1 - 各前
// 1 - テスト
// 1 - afterEach
// 2 - すべて前
// 1 - 各前
// 2 - 各前
// 2 - テスト
// 2 - afterEach
// 1 - afterEach
// 2 - すべて後
// 1 - すべて後

モック関数

jest.fn() を使用すると、モック関数を生成できます。Jest は、この関数の呼び出し、this、戻り値などをキャプチャできるため、コールバック関数をテストするときに非常に便利です。

モックのテスト

渡された配列内の各要素に対してコールバック関数を 1 回呼び出す forEach 関数の内部実装をテストするとします。

関数 forEach(items, コールバック) {
  for (let index = 0; index < items.length; index++) {
    コールバック(items[インデックス]);
  }
}

この関数をテストするには、モック関数を使用し、モック関数の状態をチェックして、コールバック関数が期待どおりに呼び出されることを確認できます。

const mockCallback = jest.fn(x => 42 + x);
forEach([0, 1], モックコールバック);

// このモック関数は2回呼び出されます。expect(mockCallback.mock.calls.length).toBe(2);

// 関数が初めて呼び出されたときの最初のパラメータは0です
期待値(mockCallback.mock.calls[0][0]).toBe(0);

// 関数を2回目に呼び出すときの最初のパラメータは1です
期待値(mockCallback.mock.calls[1][0]).toBe(1);

// 最初の関数呼び出しの戻り値は42です
mockCallback.mock.results[0].value).toBe(42) を期待します。

モック戻り値

モック関数は、テスト中にコードにテスト値を挿入するためにも使用できます。

const myMock = jest.fn();
コンソールにログ出力します。
// > 未定義

myMock.mockReturnValueOnce(10).mockReturnValueOnce('x').mockReturnValue(true);

コンソールにログ出力します。
// > 10, 'x', 真, 真

シミュレーションインターフェースの戻り

API からユーザーを取得するクラスがあると仮定します。 このクラスは axios を使用して API を呼び出し、すべてのユーザーの属性を含むデータを返します。

// ユーザー.js
'axios' から axios をインポートします。

クラスユーザー{
  静的オール() {
    axios.get('/users.json').then(resp => resp.data); を返します。
  }
}

デフォルトのユーザーをエクスポートします。

ここで、実際に API を呼び出さずにこのメソッドをテストするには (テストが遅くなり、不安定になります)、jest.mock(...) 関数を使用して axios モジュールを自動的にモックします。モジュールがモック化されたら、テスト用の偽のデータを返す mockResolvedValue を .get に提供できます。

// ユーザー.テスト.js
'axios' から axios をインポートします。
'./users' からユーザーをインポートします。

jest.mock('axios');

test('ユーザーを取得する必要があります', () => {
  ユーザーの名前を 'Bob' にします。
  const resp = {データ: ユーザー};
  axios.get.mockResolvedValue(resp);

  // または、ユースケースに応じて以下を使用することもできます。
  // axios.get.mockImplementation(() => Promise.resolve(resp))

  Users.all() を返します。その後 (data => expect(data).toEqual(users));
});

モック関数マッチャー

mock 関数を使用すると、関数にいくつかのカスタム マッチャーを追加できます。

// モック関数は少なくとも1回呼び出されました
期待する(mockFunc).toHaveBeenCalled();

// モック関数は指定された引数で少なくとも1回呼び出されました
mockFunc.toHaveBeenCalledWith(arg1, arg2) を期待します。

// モック関数への最後の呼び出しは指定された引数で呼び出されました
mockFunc.toHaveBeenLastCalledWith(arg1, arg2) を期待します。

// すべての呼び出しとモックの名前はスナップショットとして書き込まれます
(mockFunc).toMatchSnapshot() を期待します。

ネイティブ マッチャーを使用して自分でシミュレートすることもできます。次のコードは上記と同等です。
// モック関数は少なくとも1回呼び出されました
mockFunc.mock.calls.length.toBeGreaterThan(0) を期待します。

// モック関数は指定された引数で少なくとも1回呼び出されました
mockFunc.mock.calls).toContainEqual([arg1, arg2]) を期待します。

// モック関数への最後の呼び出しは指定された引数で呼び出されました
期待(mockFunc.mock.calls[mockFunc.mock.calls.length - 1]).toEqual([
  引数1、
  引数2、
]);

// モック関数の最後の呼び出しの最初の引数は `42` でした
// (この特定のアサーションにはシュガーヘルパーが存在しないことに注意してください)
期待値(mockFunc.mock.calls[mockFunc.mock.calls.length - 1][0]).toBe(42);

// スナップショットは、モックが同じ回数呼び出されたかどうかをチェックします。
// 同じ順序、同じ引数で。
mockFunc.mock.calls).toEqual([[arg1, arg2]]) を期待します。
expect(mockFunc.getMockName()).toBe('モック名');

Vue テストユーティリティ

公式サイトでは、Vue Test Utils を次のように紹介しています。

Vue Test Utils は、Vue.js の公式ユニットテスト ユーティリティ ライブラリです。

以下の例は、webpack/babel/vue-loaderを含むvue-cliスキャフォールディングに基づいています。

単一ファイルコンポーネントのテスト

Vue の単一ファイル コンポーネントは、Node またはブラウザーで実行する前に事前にコンパイルする必要があります。これを実現するには、Jest プリコンパイラを使用するか、webpack を直接使用するという 2 つの方法をお勧めします。ここでは Jest アプローチを選択します。

糸を追加 -D jest @vue/test-utils vue-jest

vue-jest は現在、カスタム ブロックやスタイルの読み込みなど、vue-loader のすべての機能をサポートしていません。さらに、コード分離などの webpack 固有の機能もサポートされていません。これらのサポートされていない機能を使用するには、Jest ではなく Mocha を使用してテストを実行し、webpack を使用してコンポーネントをコンパイルする必要があります。

webpackエイリアスの扱い

デフォルトでは、vue-cli は /src のエイリアスとして @ を使用するため、Jest でもこれを個別に設定する必要があります。

// jest.config.js

モジュール.エクスポート = {
    モジュール名マッパー: {
        '^@/(.*)$': '<ルートディレクトリ>/src/$1'
    }
}

取り付け部品

マウントされたコンポーネントはラッパーに返され、その内部の Vue コンポーネント インスタンスをカプセル化、トラバース、およびクエリするための便利なメソッドが多数公開されます。

//テスト

// test-utils ライブラリから `mount()` メソッドをインポートします // テストするコンポーネントをインポートします import { mount } from '@vue/test-utils'
'./counter' から Counter をインポートします。

// コンポーネントをマウントするとラッパーが取得されます。const wrapper = mount(Counter)

// 実際の Vue インスタンスには `wrapper.vm` 経由でアクセスできます。const vm = wrapper.vm

// ラッパーを詳しく確認するにはコンソールにログを記録します // Vue Test Utils の調査はここから始まります console.log(wrapper)

マウント中に、コンポーネントのさまざまなプロパティを設定できます。

const wrapper = mount(Counter, {
    ローカルビュー、
    データ() {
        戻る {
            バー: 'my-override'
        }
    },
    プロパティデータ: {
        メッセージ: 'abc'
    },
    parentComponent: Foo, // 親コンポーネントを指定する provide: {
        関数foo(){
            'fooValue' を返す
        }
    }
})

コンポーネントによってレンダリングされたHTMLをテストする

ラッパーの関連メソッドを使用して、コンポーネントによってレンダリングされた HTML が期待どおりであるかどうかを判断します。

'@vue/test-utils' から { mount } をインポートします。
'./counter' から Counter をインポートします。

記述('カウンター', () => {
  // コンポーネントをマウントするとラッパーが取得されます。const wrapper = mount(Counter)

  test('正しいマークアップをレンダリングします', () => {
    期待(wrapper.html()).toContain('<span class="count">0</span>')
  })

  // 既存の要素を確認するのにも便利です test('ボタンがある', () => {
    wrapper.contains('button')).toBe(true) を期待します
  })
})

ユーザーアクションをシミュレートする

ユーザーがボタンをクリックすると、カウンターが増加します。この動作をシミュレートするには、まず、ボタン要素のラッパーを返す wrapper.find() を使用してボタンを見つける必要があります。次に、ボタン ラッパーで .trigger() を呼び出すことでクリックをシミュレートできます。

it('ボタンをクリックするとカウントが増加する', () => {
  期待値(wrapper.vm.count).toBe(0)
  const ボタン = wrapper.find('ボタン')
  button.trigger('クリック')
  期待値(wrapper.vm.count).toBe(1)
})

カウンター内のテキストが更新されたかどうかをテストするには、nextTick について知っておく必要があります。 DOM の操作につながる変更はすべて、アサーションの前に nextTick を待機する必要があります。

it('ボタンをクリックするとカウントテキストが増加する', async () => {
  期待(wrapper.text()).toContain('0')
  const ボタン = wrapper.find('ボタン')
  ボタンのトリガー('クリック')を待機します。
  期待(wrapper.text()).toContain('1')
})

コンポーネントイベント

マウントされた各ラッパーは、その背後にある Vue インスタンスによって発生したすべてのイベントを自動的にログに記録します。 wrapper.emitted() メソッドを使用してこれらのイベント レコードを取得できます。

wrapper.vm.$emit('foo')
wrapper.vm.$emit('foo', 123)

/*
`wrapper.emitted()` は次のオブジェクトを返します。
{
  : [[], [123]]
}
*/

このデータに基づいてアサーションを設定できます。

// イベントが発行されたことをアサートする expect(wrapper.emitted().foo).toBeTruthy()

// イベントの数をアサートする expect(wrapper.emitted().foo.length).toBe(2)

// イベントに有効なデータがあることを確認する expect(wrapper.emitted().foo[1]).toEqual([123])

サブコンポーネントでイベントをトリガーすることもできます。

'@vue/test-utils' から { mount } をインポートします。
'@/components/ParentComponent' から ParentComponent をインポートします。
'@/components/ChildComponent' から ChildComponent をインポートします。

記述('親コンポーネント', () => {
  test("カスタムイベントが発行されたときに「発行されました!」と表示されます", () => {
    const wrapper = mount(ParentComponent)
    wrapper.find(ChildComponent).vm.$emit('custom')
    expect(wrapper.html()).toContain('発行されました!')
  })
})

コンポーネントデータ

コンポーネントの状態データを設定するには、setData() または setProps を使用できます。

it('状態を操作する', async () => {
  wrapper.setData({ count: 10 }) を待機します。

  wrapper.setProps({ foo: 'bar' }) を待機します。
})

Vueインスタンスメソッドをシミュレートする

Vue Test Utils の setMethods() は廃止される予定なので、Vue インスタンス メソッドをシミュレートするには jest.spyOn() メソッドを使用することをお勧めします。

'@/components/MyComponent.vue' から MyComponent をインポートします。

記述('MyComponent', () => {
  it('クリックすると何かが起きる', async () => {
    const mockMethod = jest.spyOn(MyComponent.methods, 'doSomething')
    shallowMount(MyComponent).find('button').trigger('click') を待ちます。
    期待(mockMethod).toHaveBeenCalled()
  })
})

グローバルプラグイン

すべてのテストで使用されるグローバル プラグインをインストールする必要がある場合は、setupFiles を使用して、最初に jest.config.js でセットアップ ファイルを指定します。

// jest.config.js
モジュール.エクスポート = {
    セットアップファイル: ['<rootDir>/tests/unit/setup.js']
}

次に、setup.js でそれを使用します。

// セットアップ.js
'vue' から Vue をインポートします

// 以下のグローバルに登録されたプラグインは Jest では動作しないため、localVue を使用する必要があります
'element-ui' から ElementUI をインポートします。
'vue-clipboard2' から VueClipboard をインポートします。

Vue.use(要素UI)
Vue.use(Vueクリップボード)

Vue.config.productionTip = false

いくつかのテストにグローバル プラグインをインストールしたいだけの場合は、一時的な Vue インスタンスを作成する localVue を使用できます。

'@vue/test-utils' から { createLocalVue, mount } をインポートします。

// 拡張された `Vue` コンストラクタを作成する const localVue = createLocalVue()

// プラグインを通常どおりインストールします localVue.use(MyPlugin)

// マウントオプションに `localVue` を渡す
マウント(コンポーネント、{
  ローカルビュー
})

テストウォッチ

次のようなウォッチャーがあるとします。

時計:
  入力値(新しい値、古い値) {
    (newVal.trim().length && newVal !== oldVal) の場合 {
      コンソールログ(新しい値)
    }
  }
}

ウォッチ呼び出しは非同期であり、次のティックまで呼び出されないため、jest.spyOn() メソッドを使用してウォッチャー内のメソッドが呼び出されたかどうかを検出することで、ウォッチが有効かどうかを検出できます。

記述('Form.test.js', () => {
  CMPをさせる
  ...

  describe('ウォッチャー - inputValue', () => {
    スパイさせて

    beforeAll(() => {
      スパイ = jest.spyOn(コンソール、'ログ')
    })

    afterEach(() => {
      spy.mockClear()
    })

    it('値が空の場合は呼び出されません(トリムされています)', () => {
    })

    it('値が同じ場合は呼び出されません', () => {
    })

    it('その他の場合には新しい値で呼び出されます', () => {
    })
  })
})

it("その他の場合には新しい値で呼び出されます", done => {
  cmp.vm.inputValue = "foo";
  cmp.vm.$nextTick(() => {
    期待(スパイ).toBeCalled();
    終わり();
  });
});

サードパーティのプラグイン

サードパーティのプラグインを使用する場合、通常は内部実装を気にする必要はなく、コンポーネントをテストする必要もありません。不要なレンダリングを減らすために、mount の代わりに shallowMount を使用できます。

'@vue/test-utils' から { shallowMount } をインポートします。

const wrapper = shallowMount(コンポーネント)
wrapper.vm // マウントされた Vue インスタンスは findAllComponents を通じてサードパーティのコンポーネントを見つけることもできます。
'element-ui' から {Select} をインポートします
test('本社を選択すると支店や店舗は表示されません', async () => {
    wrapper.setProps({を待つ
        価値: {
            クラスタータイプ: 'head-quarter-sit'、
            支店: ''、
            サイト: ''
        }
    })
    // 本社には支店や店舗は表示されません expect(wrapper.findAllComponents(Select)).toHaveLength(1)
})

VI. 結論

ユニットテスト理論

  • ユニット テストは、コードの正確性を継続的に検証し、開発を推進し、特定のドキュメントの役割を果たすことができます。
  • テストを行う際は、データは可能な限り現実をシミュレートし、内部コードではなくテストのみを考慮する必要があります。
  • テスト中にデータ境界条件を考慮する
  • 主要コード、複雑コード、コアコードのテストに重点を置く
  • ユニット テストの作成には、準備フェーズ、実行フェーズ、アサーション フェーズ、クリーンアップ フェーズというフェーズがあります。
  • ユニット テスト ツールは、テスト ランナー、テスト フレームワーク、ツール ライブラリの 3 つのカテゴリに分けられます。

冗談

  • --watch オプションを使用すると、ファイルのエンコーディングを監視し、ユニット テストを自動的に実行できます。
  • 非同期コードをテストするには、done メソッドまたは aync 関数を使用できます。
  • モック関数は、この関数の呼び出し、this、戻り値などをキャプチャできるため、コールバック関数をテストするときに非常に便利です。

Vue テストユーティリティ

  • コンポーネントをマウントし、さまざまな vue プロパティをカスタマイズするには、mount メソッドを使用します。
  • shallowMount メソッドは子コンポーネントをレンダリングしないため、テストが高速化されます。
  • setupFiles は、element-ui のインストールなど、グローバル環境を設定できます。
  • createLocalVue は、グローバル インスタンスから分離された別の vue インスタンスを作成できます。

これで、フロントエンド Vue ユニットテストの入門チュートリアルの記事は終了です。Vue ユニットテストに関するより関連性の高いコンテンツについては、123WORDPRESS.COM で過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Vue ユニットテストに推奨されるプラグインと使用例
  • Vue ユニットテストに関する予備調査
  • Vueコンポーネントのユニットテストが実際に何をテストするかについての簡単な説明
  • Vue プロジェクトにユニットテストを追加する方法
  • Vue.jsのユニットテストの書き方を教えます
  • Jest を使用して Vue プロジェクトのユニット テストを行う詳細な説明

<<:  HTML 基本要約推奨事項 (テキスト形式)

>>:  display:olck/none を使用してメニューバーを作成する方法

推薦する

Windows Server 2012 でファイル サーバーを構築するための詳細な手順

ファイル サーバーは、企業内で最も一般的に使用されるサーバーの一つであり、主にファイル共有を提供する...

ウェブインターフェースデザインでウェブサイトのスタイルガイドを作成する方法(画像とテキスト付き)

スタイル ガイドとは何でしょうか? 簡単に言えば、ストーリーを伝える方法を説明するドキュメントです。...

最高の無料英語フォント33選を紹介

チャンクファイブフリータイプファミリーCuprum JAH I フリーフォントイェセヴァブークレフィ...

最適なウェブページ幅とその互換性のある実装方法

1. Web ページをデザインするときに、幅を決定するのは非常に面倒な作業です。 jb51.net ...

Vueはページを更新するために3つの方法を使用する

プロジェクトを作成しているときに、ユーザーがアクションを実行し、特定の状態を変更し、ページを更新して...

Vueは携帯電話のカメラとアルバムを呼び出す機能を実装します

この記事では、携帯電話のカメラとアルバムにアクセスするためのVueの具体的なコードを参考までに共有し...

Alipay の Java 決済インターフェースを開発するための詳細な手順

目次最初のステップステップ2ステップ3ステップ4 Alipay 決済インターフェースへの接続に関する...

MySQL の高度な機能 - データ テーブル パーティショニングの概念とメカニズムの詳細な説明

目次パーティション分割メカニズムSELECTクエリINSERT操作DELETE操作更新操作パーティシ...

アダプティブ Web デザインの手法 (モバイル フォンでの優れたアクセス エクスペリエンス)

1. HTML ヘッダーにビューポート タグを追加します。ウェブサイトの HTML ファイルの先頭...

CSS: 訪問した疑似クラスセレクタの秘密の記憶

昨日、a:visited を使用して「Guess You Like」の右側にある訪問済みテキストの色...

ログインと登録機能を実現するjs

この記事の例では、ログインと登録機能を実装するためのjsの具体的なコードを参考までに共有しています。...

Django 2.2 を MySQL データベースに接続する方法

1. プロジェクトの実行時に報告されるエラー情報は次のとおりです。 ファイル "/home...

CSS 背景と境界タグの例の詳細な説明

1. CSS背景タグ1.背景色を設定するbackground-ground-color プロパティは...

Nginx の add_header ディレクティブに注意する必要があるのはなぜですか?

序文ご存知のとおり、nginx 構成ファイルは add_header ディレクティブを使用して応答ヘ...

複雑なSQLクエリを含むMySQLの一般的なSQL文の概要

1. 複雑なSQLクエリ1.1. 単一テーブルクエリ(1)指定の列を選択する[例] 全生徒の生徒ID...