Unit Tests JavaScript: Comprehensive 2026 Guide

javascriptの単位テスト: 2026年徹底ガイド

javascriptの単位テストをマスターするための2026年ガイド。jest、mocha、セットアップ、モッキング、CI、およびCapacitor & electronアプリ向けのtipsをカバーします。

マーティン・ドナディュー

マーティン・ドナディュー

コンテンツマーケター

Unit Tests JavaScript: Comprehensive 2026 Guide

現在、2つの状況のいずれかにいるかもしれません。JavaScriptプロジェクトがほとんどテストがなく、リファクタリングがリスクが高く感じる場合、または既存のテストが半分が遅い、脆弱で、信頼できないと感じる場合。

それが悪化するのは CapacitorElectron アプリケーションです。単純な機能が共有ビジネスロジック、ブラウザAPI、ネイティブプラグイン、ローカルファイル、IPC、リモートサービスに触れることができるため、同じフローでテストする必要があります。テスト方法が間違っていると、スイートは偽の依存関係の迷路になります。正しい方法でテストすると、論理が破壊されるたびに迅速なフィードバックが得られます。

良いユニットテストは、JavaScriptの作業は、巧妙なマッチャーシyntaxから始まるのではなく、厳格な境界から始まる。純粋な論理を直接テストし、副作用を分離し、内部関数をリネームするとテストが崩れるのを避けましょう。

目次

JavaScript テスト フレームワークを選ぶ

プロフェッショナルな JavaScript プロジェクトには、実際のテスト ランナーが必要です。アドホック スクリプトと手動コンソール チェックは、複数のエンジニアが同じコードベースに触れると、スケールしなくなります。テストの発見、断言、非同期処理、モック、CI とローカル開発で一貫して実行する方法が必要です。

現在のガイドラインは、主流のオプションに収束しています。 Jest、Mocha、Jasmine は、主なフレームワークとして繰り返し強調されています。 Jest が、組み込みのテスト構造、断言、モッキング、非同期サポートを一つのパッケージに持つことがよくあります。この Pluralsight JavaScript テスト ラボ.

JavaScript テスト フレームワークの比較表。Jest、Mocha、Cypress、Playwrightなどを含みます。

フレームワークは必須です

最初の間違いは、ユニット テストを副次的な活動として扱うことです。通常、不一致のファイル名、誰もが覚えていないカスタム断言、そして、誰もが理解できないヘルパーが生じます。

フレームワークは共通言語を提供します。

  • 構造のテストdescribetestit
  • アサーション 読みやすいマッチャーとともに
  • セットアップと破棄のためのフック 非同期サポート
  • プロミスとタイマーのための 外部依存性のためのモッキングツール
  • 外部依存性のためのモッキングツール with __CAPGO_KEEP_0__ and __CAPGO_KEEP_1__

チームが単位レベルのテスト自動化のほかに、より広いテスト自動化の視点が必要な場合、Capgo はアプリ配信ワークフローの自動テストについて便利な概要を提供しています。 アプリ配信ワークフローの自動テスト.

Jest と Mocha の比較

Jest と Mocha は 2 つの異なる哲学を表しています。

Jest Jest は、チームが最初の日から必要なほぼすべてのものを含むオールインワンのオプションです。
Mocha Mocha はモジュラーで、ランナーと残りのスタックを組み立てることを期待しています。

機能JestMocha
セットアップの複雑さほとんどのチームでは低い通常、アサーションとモッキングライブラリを追加するため、より高い
アサーション組み込み通常、他のライブラリと組み合わせて使用
モッキング組み込み通常、他のライブラリと組み合わせて使用
非同期テスト組み込みで簡単サポートされているが、周囲の設定に依存する
カバレッジワークフローよく統合されるツールチェーンしばしば組み合わせる
最も適切な選択新しいプロジェクト、統一性を求めるチーム既存のスタック、モジュラーな制御を求めるチーム

実用的なルール チームが、実行者と組み合わせるアサーションライブラリとモッキングライブラリを選択する必要がある場合、Jestを使用したいと思います。

大多数のチーム向けの推奨事項

大多数の現代的なプロジェクトの場合、Mochaに留まる理由がすでにコードベースにある場合を除き、Jestを選択することをお勧めします。 Jest アプリケーションが含む場合、Mochaに留まる理由がすでにコードベースにある場合を除き、Jestを選択することをお勧めします。 Capacitor or Electron, そのプロジェクトはすでに十分な動きのあるパーツを持っているため、Electron などは使用しない。

テストツールのスプレッドが減ることで、すぐに効果が現れます。

Mocha は、古い Node.js サービスや長期間にわたるコードベースで、周囲のエコシステムがすでに確立されている場合には、まだ意味があります。

しかし、mid-level エンジニアが、最初からロバストなスイートを設定する場合、Jest は、より多くの摩擦を生み出すことよりも、より多くの摩擦を削減します。

重要な範囲の注釈。Cypress と Playwright は、優れたツールですが、異なる問題を解決します。

ブラウザレベルとエンドツーエンドのチェックに適していますが、ユニットテストのJavaScriptの作業が住むべきは、高速な内部ループではありません。

プロジェクトのセットアップと最初のテスト

クリーンなテストセットアップは、面白くないものでなければなりません。 package.json最初のテストを追加することで、複雑さが生じる場合、スイートは健康に維持されない可能性があります。

{
  "scripts": {
    "test": "jest"
  }
}

眼鏡をかけた男性が、木製の机の上でプログラミングプロジェクトに取り組んでいるラップトップを操作しています。

ローカルで Capacitor アプリを構築している場合、開発環境を整理したいのであれば、Capgoのローカル環境設定ガイドを Capacitor ローカル環境の設定 __CAPGO_KEEP_0__ ローカル環境の設定は実用的なパートナーです。

code のテストを書く

テストを最初に書くパターンは、単に個人的な好みではありません。米国消費者金融保護局のJavaScriptガイドラインでは、 テストを最初に書くテストを組織化する describeitexpect(...) テストのフレームワークを設定する テストのフレームワークを設定する.

That matters because test-first changes how you design code. Functions tend to become smaller, dependencies become more visible, and side effects stop leaking into logic that should stay pure.

最小の例を以下に示します。

// math.js
function addTax(amount, rate) {
  return amount + amount * rate;
}

module.exports = { addTax };
// math.test.js
const { addTax } = require('./math');

describe('addTax', () => {
  it('returns the amount with the tax applied', () => {
    expect(addTax(100, 0.2)).toBe(120);
  });
});

Arrange Act Assertを常に使用する

この Arrange, Act, Assert パターンは、テストが複雑になるにつれても、読みやすく保たれます。

  1. 入力と必要なセットアップを 関数を呼び出す
  2. 結果について 検証ヘルパーに適用
  3. __CAPGO_KEEP_0__ __CAPGO_KEEP_1__

__CAPGO_KEEP_2__

function isSupportedPlatform(platform) {
  return ['ios', 'android', 'web', 'desktop'].includes(platform);
}

describe('isSupportedPlatform', () => {
  it('returns true for ios', () => {
    // Arrange
    const platform = 'ios';

    // Act
    const result = isSupportedPlatform(platform);

    // Assert
    expect(result).toBe(true);
  });
});

小さなテストは長く生きる。テストは通常、1 つの質問に答えるようにするべきであり、全体のワークフローを語るべきではない。

Capgo と Electron のプロジェクトの場合、 Capacitor と native または desktop の統合が混在するため、純粋な論理がしばしばその隣にあります。 code からプラットフォーム ランタイムを除外して、ビジネス ルールをテスト可能にし、最初のテストが最後の有用なテストではないことを保証します。

モックと非同期 Code のマスター

アプリケーション code の多くのバグは、2 つの数字を加算することによるものではなく、 code が外部に影響を与えるものです: ネットワーク リクエスト、ファイル、プラグイン API、タイマー、IPC チャネル、ストレージ レイヤー。

モッキングは、境界を制御することで、テストが code の決定を焦点に置くことができるため、そこで役立ちます。

API、データ ストア、外部サービス、イベント ドリブン データ フローを示す白板図。

境界をモックする、すべてではない

テストの持続可能性を強調する指針は 単一の行動カバレッジ そして 1 つの強力なアサーションごとにテスト, そして、モッキングを過度に使用すると、テストが実装の詳細に密接に結びつき、脆弱になることを警告しています。 単位テストの持続可能性に関するTestRail記事.

JavaScriptにおける警告は非常に重要です。チームは、すべてのインポートモジュールを偽装し、機能が他の機能を「正しく」呼び出すかどうかをテストするのではなく、実際の動作をテストするのではなく、始めます。

偽装が多く含まれるテストの不適切な対象

  • ヘルパーAがヘルパーBを呼び出したかどうか
  • サービスCがシリアライザーDを呼び出したかどうか
  • 内部プライベート関数が2回実行されたかどうか

より適切な対象

  • 関数が何を返したか
  • 依存関係が失敗した場合に正しく処理されたか
  • データを期待どおりに変形したか

より適切なパターン: CapacitorとElectron code

モバイルとデスクトップアプリでは、ネイティブまたはプラットフォームAPIのラッパー層を使用し、ラッパーを偽装することでユニットテストを実行します。プラットフォーム自体を偽装するのではなく

例の構造:

// cameraGateway.js
async function getPhoto(cameraPlugin) {
  return cameraPlugin.getPhoto();
}

module.exports = { getPhoto };
// profilePhotoService.js
async function loadProfilePhoto(cameraGateway) {
  const photo = await cameraGateway.getPhoto();
  return { path: photo.path, ready: true };
}

module.exports = { loadProfilePhoto };
// profilePhotoService.test.js
const { loadProfilePhoto } = require('./profilePhotoService');

test('returns mapped photo data', async () => {
  const fakeCameraGateway = {
    getPhoto: jest.fn().mockResolvedValue({ path: '/tmp/pic.jpg' })
  };

  const result = await loadProfilePhoto(fakeCameraGateway);

  expect(result).toEqual({ path: '/tmp/pic.jpg', ready: true });
});

Electron も同様に機能します。Wrap ipcRendererファイルアクセス、またはシェル統合を、薄いアダプターの背後で実行します。ユニットテストはサービス層に当たりますが、直接実行時には当たりません。

チームがリリースロジックとアップデートパスを Capacitor アプリでテストしている場合、Capgo は Capacitor OTA のアップデートをシナリオモックでテストするためのガイドを提供しています。 アプリの Capacitor の OTA のアップデートをシナリオモックでテストするためのガイド.

チームがまだ非同期テストスタイルを標準化していない場合、簡単なウォークスルーが役立ちます。

非同期フローをフラッキーのないテストでテストする

テストで __CAPGO_KEEP_0__ がプロミスを返す場合に使用します。コールバックが多く含まれるパタームよりも明確で、デバッグも容易です。 async/await in tests when the code under test returns a promise. It’s clearer than callback-heavy patterns and easier to debug.

async function fetchProfile(api) {
  const response = await api.getUser();
  return response.name;
}

test('returns the user name from the API response', async () => {
  const api = {
    getUser: jest.fn().mockResolvedValue({ name: 'Ava' })
  };

  const result = await fetchProfile(api);

  expect(result).toBe('Ava');
});

ハッピーパスとアグリーペスを両方テストしてください。生産環境では、アグリーペスはユーザーが思い出すのが多いパスです。

test('throws when the API request fails', async () => {
  const api = {
    getUser: jest.fn().mockRejectedValue(new Error('network failed'))
  };

  await expect(fetchProfile(api)).rejects.toThrow('network failed');
});

強力なテストのための高度な戦略

__CAPGO_KEEP_1__

テストスイートは、codeの変更が行われた後でも有用である場合にのみ、有用である。

テストカバレッジとメンテナブルなテストスイートを通じて堅牢なソフトウェアを構築するための戦略を示す図。

テスト分割を予算として使用する。

1つの実用ガイドでは、 70/20/10 単体テスト、統合テスト、エンドツーエンドテストの を分割することを推奨しています。単体テストは最速のフィードバックと最も安定したエラーを提供します。 このOpenReplayテストガイドによると、完全な単体テストスイートは理想的には 秒以内に完了し、秒以内に完了する必要があります。 このガイドは、.

Iはそれを予算管理ツールとして扱いますが、宗教ではありません。 ほとんどの努力がエンドツーエンドテストに費やされると、チームはフィードバックの待ち時間が長くなります。 一切が単体テストのみの場合、実際のシステム境界を無視することになります。

ElectronアプリまたはCapacitorアプリの場合、健康的なバランスは通常以下のようになります。

  • 単体テスト 価格ロジック、権限ルール、シリアライズ、更新有効性、機能フラグ、状態変換のテスト
  • 統合テスト ストレージアダプタ、プラグインラッパー、IPCコントラクトのテスト
  • エンドツーエンドテスト ログイン、購入フロー、同期、または更新ポップアップなどの重要なジャーニーをテストする

カバレージはフラッシュライトではなく目標ではありません。

カバレージレポートは、重要なロジックの未テストブランチを発見するのに役立ちますが、チームがカバレージパーセンテージを追求することで害を及ぼします。

エッジケースを考慮したログインバリデーターのテストは、単にカバーされたファイルにトリビアルなアサーションを含むファイルよりも価値があります。 それが特に、入力が多いcode、例えばフォーム、パーサー、日付ロジック、権限チェックの場合です。 チームがバリデーションヘビーなUIの品質を高めている場合、このガイドを参照してください。 フロントエンドフォームバリデーションをマスターする 単位レベルのテスト戦略の補完として機能します。

ビヘイビアファーストのテストはリファクタリングを乗り切る

信頼できるスイートは、内部のリファクタリングを行うと、半分のテストを書き直すことなく、テストを書き直すことができるようにする必要があります。そこに到達する最も簡単な方法は、実装の詳細ではなく、観察可能な動作を主張することです。 機能するケース: 境界条件

空の入力、nullのような値、無効な型、オーバーサイズの文字列など

  • ドメインの結果 例えば、「許可されていない権限がないため返却される」
  • 状態の移行 例えば、「ダウンロードメタデータが検証された後、更新を保留状態としてマークする」
  • __CAPGO_KEEP_0__ __CAPGO_KEEP_0__

使用するケースがよく変化する:

  • 内部ヘルパー呼び出しを検査する
  • プライベートメソッドのシーケンスを確認する
  • 呼び出しチェーンのすべての層をモックする

アプリ開発チームが厳格なリリースプロセスを構築している場合、Capgoの記事「 アプリの品質保証 」は、テストワークをより広範なリリースパイプラインと関連付けることで、有用である。

CI、Capacitor、およびElectronアプリのテスト

1人の開発者のマシン上で実行されるテストだけでは、安全ネットではありません。ローカルな習慣です。

CIは、ユニットテストのJavaScriptワークをチームインフラに変換します。プッシュ、プルリクエスト、またはリリースブランチごとに、同じコマンドと同じ期待値でテストを実行できます。その一貫性は、CapacitorおよびElectronプロジェクトでは、環境の変化が微妙なエラーを引き起こすため、より重要です。

CIをデフォルトの実行パスに設定する

CIは、少なくとも依存関係のインストールとユニットスーツの実行を、すべての変更セットごとに実行する必要があります。可能な限りローカル開発と同じコマンドを使用してください。

A basic GitHub の Actions ワークフローは、以下のように簡単に実装できます。

name: test

on: [push, pull_request]

jobs:
  unit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test

主なコードに到達する前に、破損したインポート、失敗したアサーション、誤ったプラットフォームの仮定をキャッチするのに十分です。

自動化されたパイプラインを通じてモバイルチームが配信する場合、Capgoには、CapgoアプリのCI/CD設定の実用ガイドがあります。 Capacitor プラグインの相互作用をテストする.

Capacitor __CAPGO_KEEP_1__のユニットテストの間違った方法は、各サービスにネイティブのプラグインを直接pullすることです。 これは、プラットフォームブリッジにテストスイートを結びつけることです。

The wrong way to unit test Capacitor code is to pull native plugins directly into every service. That couples your test suite to the platform bridge.

カメラアクセス、バイオメトリックのプロンプト、プッシュトークンの登録、ネットワークのステータスも同様です。 アダプター内でプラグインの呼び出しを維持し、制御できるインターフェイスに対してアプリロジックをテストします。

// deviceStorage.js
async function saveFile(filesystem, path, data) {
  return filesystem.writeFile({ path, data });
}

module.exports = { saveFile };
// draftService.js
async function persistDraft(storage, draft) {
  await storage.save('draft.json', JSON.stringify(draft));
  return { saved: true };
}

module.exports = { persistDraft };
// draftService.test.js
const { persistDraft } = require('./draftService');

test('persists a serialized draft', async () => {
  const storage = {
    save: jest.fn().mockResolvedValue(undefined)
  };

  const result = await persistDraft(storage, { title: 'Hello' });

  expect(result).toEqual({ saved: true });
});

ElectronのメインレンダラーとIPC __CAPGO_KEEP_0__のテスト

Testing Electron main renderer and IPC code

メインプロセス __CAPGO_KEEP_0__ main process code __CAPGO_KEEP_0__ レンダラー プロセス code. テストでぼやかさを消さないで。

信頼できるセットアップは通常、以下を分離する:

  • レンダラー単体テスト ビュー モデル、状態、フォーマット、UI側のビジネス ロジック
  • メイン プロセス単体テスト メニュー、ファイル オペレーション、アプリ ライフサイクル決定
  • IPC契約テスト メッセージの形状と期待される応答

例のIPCラッパー:

// ipcGateway.js
function sendSettings(ipcRenderer, payload) {
  ipcRenderer.send('settings:update', payload);
}

module.exports = { sendSettings };
// ipcGateway.test.js
const { sendSettings } = require('./ipcGateway');

test('sends settings update over ipc', () => {
  const ipcRenderer = { send: jest.fn() };

  sendSettings(ipcRenderer, { theme: 'dark' });

  expect(ipcRenderer.send).toHaveBeenCalledWith('settings:update', { theme: 'dark' });
});

If you later change the internal implementation from one helper to another, this test still holds because it verifies the behavior that matters. That’s the standard you want across desktop and mobile code.

JavaScript単体テストについてよくある質問

What’s the difference between unit integration and E2E tests

A 単位テスト 単位テストは、1 つの小さなロジックを孤立してチェックします。統合テストは、複数のコンポーネントやサービスが正しく機能するかどうかをチェックします。エンドツーエンドテストは、実行中のアプリケーションを通してユーザージャーニーを実行します。 単位テストはビジネスルールに対する迅速な信頼のために使用してください。統合テストは、ストレージ、プラグインラッパー、IPCなどのシームズに対して使用してください。E2Eテストは、壊れた場合に大きな影響を与えるワークフローに対してsparingly使用してください。 完全なカバレージを目指すべきか いいえ。完全なカバレージは、チームを低価値のテストに誘導する可能性があります。 カバレージは、誰も実行していないリスクのある__CAPGO_KEEP_0__を明らかにするのに役立ちます。ダッシュボードを満たすために、エンジニアが浅いアサーションを追加するのを止めるには役立ちません。スイートが脆い場合、カバレージがそれを救うことはありません。

Should we aim for full coverage

No

Coverage is useful when it reveals risky __CAPGO_KEEP_0__ that nobody has exercised

Coverage is useful when it reveals risky code that nobody has exercised. It’s not useful when engineers add shallow assertions just to satisfy a dashboard. If your suite is brittle, more coverage won’t save it.

既存のコードベースにテストを追加する方法は?

変更が既に発生している場所から始めましょう。チームを凍結せずに、テスト戦略の大規模なリライトを発表するのを避けましょう。

実践的なシーケンスは次のようになります。

  • codeを保護する 機能開発やバグ修正の際に触れるモジュールにテストを追加する
  • 純粋なロジックを抽出する フレームワークやランタイムのノイズが混入しないようにビジネスルールをテストする
  • ネイティブプラグイン、ネットワーククライアント、ファイルシステム呼び出し、Electron IPC周りのシームワッパーを追加する モックを導入する際に脆弱なパターンを拒否する
  • JavaScriptテストのベストプラクティスから指導を受ける テスト戦略のリライトは大きな変更を伴うため、チームを凍結するのではなく、実際の問題に対処するためのテストを段階的に導入することが推奨されます。 テストを導入する際に、既存のコードを変更せずにテストを実行できるようにすることが重要です。 特にここでは、オーバーモッキングがよく見落とされる問題と、その後に続く脆弱なテストを強調するため、ここでは特に役立ちます。

目標は即時的な完全性ではありません。チームにとって最もコストがかかる場所での、徐々に改善することです。


チームが Capacitor または Electron アプリを開発し、JavaScriptの変更に対してよりきれいなリリースプロセスが必要な場合、 Capgo はオプションの1つです。CapacitorJSとElectronアプリに対してリアルタイムの更新を提供し、ロールアウトの制御と観察性を備え、チームは単体テストとともに、ストアのレビューを待たずにウェブバンドルの変更を安全に実装できるようにします。

Capacitor アプリのリアルタイム更新

Capgo を使用して、ウェブ層のバグが生じた場合、修正をアプリストアの承認待ちの日数を待たずに配信できます。ユーザーはバックグラウンドで更新を受け取り、ネイティブの変更は通常のレビュー経路を通じて残ります。

スタート

ブログの最新記事

Capgo を使用すると、プロフェッショナルなモバイルアプリを作成するために必要な最良の洞察を得ることができます。