ホームページ  >  記事  >  ウェブフロントエンド  >  Jest を使用した一例におけるユニット、統合、ETesting

Jest を使用した一例におけるユニット、統合、ETesting

DDD
DDDオリジナル
2024-11-20 19:53:15236ブラウズ

導入

多くの開発者は、コードをテストする際に課題に直面しています。適切なテストがなければバグがすり抜け、ユーザーの不満や高額な修正につながる可能性があります。

この記事では、Node.js と MongoDB を使用して構築された非常に単純な例に、Jest、Supertest、および Puppeteer を使用して単体テスト、統合テスト、エンドツーエンド テストを効果的に適用する方法を示します。

この記事を読み終えるまでに、この種のテストを独自のプロジェクトに適用する方法を明確に理解していただければ幸いです。

?‍?このリポジトリで完全な例を見つけてください。

依存関係の紹介

依存関係をインストールする前に、まず例を紹介します。これは、ユーザーが登録ページを開いて登録の詳細を設定し、登録ボタンをクリックして、その情報をデータベースに保存できる非常に単純な例です。

この例では、次のパッケージを使用します:

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all

これらの依存関係のほとんどは簡単ですが、いくつかについては以下で説明します。

  • puppeteer: 自動テストと Web スクレイピングのためにヘッドレス ブラウザ (Chrome) を制御できます。
  • Jest-Puppeteer: Puppeteer を統合する Jest 用にプリセットされており、ブラウザー環境でエンドツーエンドのテストを実行するためのセットアップを簡素化します。これを jest.config.js ファイルのプリセットとして使用でき、jest-puppeteer.config.js というファイルを通じて Puppeteer の動作をカスタマイズできます。
  • mongodb-memory-server: データベース相互作用の高速かつ分離されたテストのために、メモリ内の MongoDB インスタンスを起動するユーティリティです。
  • npm-run-all: 複数の npm スクリプトを並列または順次に実行する CLI ツール。

単体テスト

  • 定義: 単体テストは、個々のコンポーネントまたは機能を分離してテストすることに焦点を当てます。目標は、コードの各ユニットが期待どおりに実行されることを検証することです。
  • 速度: 単体テストは外部システムやデータベースに依存せずに小さなコード部分をテストするため、通常は非常に高速です。
  • : ユーザー登録の例では、単体テストで電子メール アドレスを検証する関数をチェックします。たとえば、関数が user@example.com を有効なものとして正しく識別し、user@.com または user.com を拒否しているかどうかを検証します。

わかりました。これをコードに変換しましょう。

単体テスト環境のセットアップ

予測できない動作を起こさずに単体テストを実行するには、各テストの前にモック関数をリセットする必要があります。これは、beforeEach フックを使用して実現できます:

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 

電子メール検証のテスト

この場合、validateInput 関数をテストします。

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all

これは、提供された入力に有効な電子メールが含まれているかどうかを検証する非常に単純な関数です。これがその単体テストです:

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 

await Expect(async () => {}).rejects: Jest ドキュメントに基づいて、これは拒否された Promise の理由を予想する方法です。

重複したメールのテスト

データベース内に重複した電子メールが存在するかどうかを確認する別の関数をテストしてみましょう。実際、これは興味深いものです。なぜなら、データベースを扱わなければならないと同時に、単体テストでは外部システムを扱うべきではないからです。それでは何をすべきでしょうか?そうですね、Mock を使用する必要があります。

まず、テストする必要がある emailShouldNotBeDuplicated 関数を見てください。

// register.controller.js
const validator = require('validator');

const registerController = async (input) => {
  validateInput(input);
  ...
};

const validateInput = (input) => {
  const { name, email, password } = input;
  const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 });
  if (!isValidName) throw new Error('Invalid name');
  ...
};

ご覧のとおり、この関数はデータベースにリクエストを送信し、同じ電子メールを持つ別のユーザーがいるかどうかを確認します。データベース呼び出しをモックする方法は次のとおりです:

// __tests__/unit/register.test.js
const { registerController } = require('../controllers/register.controller');

describe('RegisterController', () => {
  describe('validateInput', () => {
    it('should throw error if email is not an email', async () => {
      const input = { name: 'test', email: 'test', password: '12345678' };
      await expect(async () => await registerController(input)).rejects.toThrow('Invalid email');
    });
  });
});

私たちは、モック関数を作成し、その呼び出しを追跡する jest.spyOn(object, methodName) を使用して、データベースの findOne メソッドをモック (スパイ) しました。その結果、toHaveBeenNthCalledWith.

を使用して、スパイされた findOne メソッドの呼び出し数と渡されたパラメーターを追跡できます。

統合テスト

  • 定義: 統合テストでは、複数のコンポーネントがどのように連携して動作するかを評価します。さまざまな機能、モジュール、またはサービス間の相互作用をチェックします。
  • 速度: 統合テストには複数のコンポーネントが含まれ、データベース アクセスやネットワーク呼び出しが必要になる場合があるため、統合テストは単体テストよりも遅くなります。
  • : ユーザー登録プロセスの場合、登録リクエストの送信時にユーザー データが正しく検証され、データベースに保存されていることを統合テストで検証できます。このテストでは、入力検証、API エンドポイント、データベース インタラクションなどのすべてのコンポーネントが意図したとおりに連携して動作することを確認します。

統合テスト環境のセットアップ

統合テストを作成する前に、環境を構成する必要があります。

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all
  • ご覧のとおり、統合テストで必要になるため、 testingApp をエクスポートします。そして、これを関数としてエクスポートします。完全に初期化される前にエクスポートされるためです。beforeAll が非同期であるため、testingApp に値が割り当てられる前に module.exports ステートメントが実行されるため、テストで使用しようとすると未定義になります。ファイル。
  • Jest フックを使用することで、次のことが可能になりました。
    • beforeAll: Express サーバーを起動し、メモリ内の MongoDB データベースに接続します。
    • afterAll: Express サーバーを閉じ、実行中のメモリ内 MongoDB データベースを停止します。
    • beforeEach: 各テスト ケースの前にユーザー コレクションを削除してデータベースをクリーンアップします。

これで、統合テストを実行する準備が整いました。

登録 API リクエストのテスト

登録リクエストの送信からデータベースへのユーザー詳細の保存、成功ページへのリダイレクトまで、サーバー側の登録プロセス全体をテストしてみましょう:

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 

ご覧のとおり、registerController 関数は、validateInput、emailShouldNotBeDuplicated、createUser 関数といった複数のコンポーネント (関数) を統合しています。

それでは、統合テストを書いてみましょう:

// register.controller.js
const validator = require('validator');

const registerController = async (input) => {
  validateInput(input);
  ...
};

const validateInput = (input) => {
  const { name, email, password } = input;
  const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 });
  if (!isValidName) throw new Error('Invalid name');
  ...
};
  • ご覧のとおり、このテストケースでは、supertest パッケージを使用して登録リクエストを API に送信します。これにより、登録プロセス中の実際のユーザーの行動がシミュレートされます。
  • この場合、実際の動作をテストする必要があるため、データベース呼び出しをモックしませんでした。

エンドツーエンド (E2E) テスト

  • 定義: E2E テストは、実際のユーザー シナリオをシミュレートして、アプリケーション フロー全体を最初から最後まで検証します。ユーザー インターフェイスやバックエンド サービスを含む、アプリケーション全体をテストします。
  • 速度: E2E テストは、アプリケーション インターフェイスを介して移動し、さまざまなコンポーネントと対話する必要があり、多くの場合複数のネットワーク リクエストが必要となるため、3 つのタイプの中で最も遅いです。
  • : ユーザー登録のコンテキストでは、E2E テストは、ユーザーが登録ページを開いて詳細 (名前、電子メール、パスワードなど) を入力し、「登録」ボタンをクリックすることをシミュレートします。 、成功ページにリダイレクトされるかどうかを確認します。このテストは、ユーザーの観点から、登録プロセスのすべての部分がシームレスに連携していることを検証します。

例に移りましょう。

E2E テスト環境のセットアップ

実際、この例では、エンドツーエンド テストの環境構成は統合テストの環境構成と似ています。

登録プロセスを最初から最後までテストする

この場合、登録ページを開いて詳細 (名前、電子メール、パスワード) を入力し、「登録」ボタンをクリックして、最終的に成功ページにリダイレクトされるまでの、実際のユーザー登録動作を正確にシミュレートする必要があります。 。コードを見てください:

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all

このコードを分解してみましょう:

  • エンドツーエンド テストの実装に使用できるツールは多数あります。ここでは、Jest と Puppeteer を使用してエンドツーエンド テストを実装します。
  • ページ変数とは何なのか疑問に思われるかもしれません。 Jest と同様、これは Puppeteer によって提供されるグローバル変数であり、要素の移動や操作などのアクションを実行できるブラウザーの単一のタブを表します。
  • Puppeteer を使用して、goto 関数を使用してそのページを開き、type 関数を使用して入力を入力し、click 関数を使用して登録ボタンをクリックするというユーザーの動作をシミュレートしています。

異なる構成ですべてのテストを一緒に実行する

Unit, Integration, and ETesting in One Example Using Jest

Unsplash の Nathan Dumlao による写真

この時点で、それぞれに独自の構成がある場合に、すべてのテスト タイプを同時に実行する方法を疑問に思うかもしれません。例:

  • 単体テストでは、すべてのテスト ケースの前にすべてのモックをリセットする必要がありますが、統合テストではこれは必要ありません。
  • 統合テストでは、テストを実行する前にデータベース接続を設定する必要がありますが、単体テストではこれは必要ありません。

では、それぞれのテスト タイプが対応する設定を確実に尊重しながら、すべてのテスト タイプを同時に実行するにはどうすればよいでしょうか?

この問題に対処するには、次の手順に従ってください:

1. 3 つの異なる設定ファイル jest.unit.config.js を作成しましょう:

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 

jest.integration.config.js:

// register.controller.js
const validator = require('validator');

const registerController = async (input) => {
  validateInput(input);
  ...
};

const validateInput = (input) => {
  const { name, email, password } = input;
  const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 });
  if (!isValidName) throw new Error('Invalid name');
  ...
};

jest.e2e.config.js:

// __tests__/unit/register.test.js
const { registerController } = require('../controllers/register.controller');

describe('RegisterController', () => {
  describe('validateInput', () => {
    it('should throw error if email is not an email', async () => {
      const input = { name: 'test', email: 'test', password: '12345678' };
      await expect(async () => await registerController(input)).rejects.toThrow('Invalid email');
    });
  });
});

2. 次に、package.json ファイル内の npm スクリプトを次のように更新します。

// register.controller.js
const { User } = require('../models/user');

const registerController = async (input) => {
    ...
  await emailShouldNotBeDuplicated(input.email);
  ...
};

const emailShouldNotBeDuplicated = async (email) => {
  const anotherUser = await User.findOne({ email });
  if (anotherUser) throw new Error('Duplicated email');
};

--config: Jest 構成ファイルへのパスを指定します。

npm-run-all --Parallel: すべてのテストを並行して実行できます。

3. 次に、setup.unit.js、setup.integration.js、setup.e2e.js という名前の 3 つのセットアップ ファイルを作成します。これには、前のセクションで使用した必要なセットアップ コードが含まれています。
4. 最後に、このコマンド npm run test を実行して、すべてのテストを実行します。このコマンドは、すべての単体テスト、統合テスト、およびエンドツーエンド テストをそれぞれの構成に従って並行して実行します。

結論

この記事では、単体テスト、統合テスト、エンドツーエンド (E2E) テストについて検討し、信頼性の高いアプリケーションを構築するためのそれらの重要性を強調しました。 Node.js と MongoDB を使用した簡単なユーザー登録の例で、Jest、Supertest、Puppeteer を使用してこれらのテスト メソッドを実装する方法を示しました。

実際、堅実なテスト戦略はコードの品質を向上させるだけでなく、開発者の自信を高め、ユーザーの満足度も高めます。

この記事が、あなた自身のプロジェクトに適用できる有益な洞察を提供することを願っています。テストを楽しんでください!

考えてみてください

この記事が役立つと思われた場合は、次の記事もチェックしてください:

  • MongoDB GridFS をシンプルにしました
  • FFmpeg と Node.js を使用してビデオ ストリーミングを改善した方法
  • 非同期 JavaScript を処理する 4 つの方法

ここまでお付き合いいただき、誠にありがとうございました。この記事を楽しんで読んでいただければ幸いです。

以上がJest を使用した一例におけるユニット、統合、ETestingの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。