メインコンテンツにジャンプ

Unit Tests JavaScript: Comprehensive 2026 Guide

javascriptの単体テストをマスターするための2026年ガイドです。 Jest、Mocha、セットアップ、モッキング、CI、およびCapacitorおよびElectronアプリ向けのアドバイスをカバーしています。

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

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

コンテンツマーケター

Unit Tests JavaScript: Comprehensive 2026 Guide

You’re probably in one of two situations right now. Either your JavaScript project has almost no tests and every refactor feels risky, or you already have tests and half of them are slow, brittle, and oddly hard to trust.

が悪化するのは CapacitorElectron アプリケーションです。 1 つの機能が共有のビジネスロジック、ブラウザ API、ネイティブ プラグイン、ローカル ファイル、IPC、リモート サービスに触れる場合、テストを間違った方法で実行すると、スイートは偽の依存関係の迷路になります。 正しい方法でテストを実行すると、破綻するロジックに高速なフィードバックが得られます。

良いユニット テストは、JavaScript の作業は、巧妙なマッチャー構文で始まるのではなく、規則正しい境界から始まります。純粋なロジックを直接テストし、副作用を分離し、内部関数をリネームするとすぐにテストが崩壊しないようにテストを書く必要があります。

目次

JavaScriptテストフレームワークの選択

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

現在のガイドラインは、主流のオプションに集中しています。 Jest、Mocha、Jasmine は、再び主なフレームワークとして強調されています。 __CAPGO_KEEP_0__ は、組み込みのテスト構造、断言、モッキング、非同期サポートを1つのパッケージに提供しているため、よく単独で取り上げられます。この のJavaScriptテストラボ.

が示すように。

JavaScriptテストフレームワークの比較表

Jest

Mocha

  • Cypress Playwright。 describe フレームワークは必須です。 test チームが最初に犯す間違いは、ユニットテストを副次的な活動として扱うことです。通常、これは不一致のファイル名、誰も覚えていないカスタム断言、そして誰もが理解できないヘルパーに至ります。 it
  • アサーション 読みやすいマッチャーとともに
  • フック セットアップと解放のために
  • 非同期サポート プロミスとタイマー
  • 外部依存性のモッキングツール あなたのチームも、ユニットレベルの作業を超えたテスト自動化のより広い視点が必要な場合、__CAPGO_KEEP_0__ はアプリの配信ワークフローにおける自動テストの概要を提供しています。

If your team also needs a broader view of test automation beyond unit-level work, Capgo has a useful overview of Jest と Mocha は、異なる哲学を表しています。.

自動テストの概要

Jest と Mocha の概要

Jest __CAPGO_KEEP_0__
Mocha __CAPGO_KEEP_1__

機能JestMocha
セットアップの複雑さほとんどのチームでは低い高くなることが多い。通常、検証とモッキングライブラリを追加する必要があるため
検証組み込まれている通常は別のライブラリと組み合わせて使用
__CAPGO_KEEP_0____CAPGO_KEEP_0__通常は別のライブラリと組み合わせて使用
非同期テスト__CAPGO_KEEP_0____CAPGO_KEEP_0__
カバレッジフロー同じツールチェーンに統合されることが多いより多くの部分が組み合わせられている
最も適切な選択新しいプロジェクト、統一性を求めるチーム古典的なスタック、モジュラー制御を望むチーム

実用的ルール: チームがランナーと組み合わせるべきアサーションライブラリとモッキングライブラリを尋ねなければならない場合、Jestを使いたいと思います。

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

大多数の現代的なプロジェクトでは、 Jest Mochaがすでに強固な理由でコードベースに残っている場合を除いて、推奨します。その推奨は、 Capacitor 、または Electronを含むアプリケーションがある場合にさらに強まります。テストツールのスプレッドを削減すると、すぐに効果が現れます。

Mochaは、既に安定したエコシステムを持つ古いNode.jsサービスまたは長期間のコードベースでまだ意味がありますが、ミドルレベルエンジニアがスクラッチから強力なセットを設定する場合、Jestは通常、より多くの摩擦を生み出さずに、より多くの摩擦を削減します。

重要なスコープの注釈。CypressとPlaywrightは優れたツールですが、別の問題を解決するものです。ブラウザレベルとエンドツーエンドのチェックに適していますが、ユニットテストのJavaScriptの作業が行われる高速な内部ループではありません。

プロジェクトの設定と最初のテスト

テストの設定がきれいなものであれば、面白くないはずです。最初のテストを追加することが複雑な場合、スイートは健康に維持されないでしょう。

木製の机の上でプログラミングプロジェクトに取り組む男性が、眼鏡をかけている。

シンプルなJestの設定

JavaScriptプロジェクトがすでにあります。 package.jsonJestを開発依存モジュールとして追加し、テストスクリプトを設定してください。

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

これで多くのプロジェクトでは十分です。モジュールシステム、トランスピラーション、またはモノレポ構造が必要な場合は、後で追加することができます。

ローカルでCapacitorアプリを構築中で、共有ロジックの周りにテストを追加する前に開発環境を整える場合は、Capgoの setting up a Capacitor local environment のガイドは実用的な相談相手です。

テストをcodeで書く

テストファーストパターンは、単に個人的な好みではありません。米国消費者金融保護局のJavaScriptガイドラインでは、明示的に __CAPGO_KEEP_0__をテストする前に書くこと describe 、テストを itexpect(...) で組織すること 、チェックを.

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. 小さなテストは長く生きる。テストは通常、1 つの質問に答えるべきであり、全体のワークフローを語るべきではない。 Capgo と Electron プロジェクトの場合、 __CAPGO_KEEP_0__ とネイティブまたはデスクトップ統合の __CAPGO_KEEP_1__ の間で、純粋なロジックがしばしば並ぶため、この規則はより重要である。プラットフォームの実行時を伴わないビジネスルールのテストを実行可能にし、最初のテストが最後の有用なテストではないようにする。

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

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);
  });
});

アプリケーション __CAPGO_KEEP_0__ の多くのバグは、2 つの数字を加算することから来るものではない。 __CAPGO_KEEP_1__ が外部に影響を与えるものが原因である。ネットワーク要求、ファイル、プラグイン API、タイマー、IPC チャネル、ストレージ レイヤーなどが原因である。

For Capacitor and Electron projects, that discipline matters more because your pure logic often sits next to native or desktop integration code. Keep the business rule testable without the platform runtime, and your first test won’t be your last useful one.

Mastering Mocks and Asynchronous Code

Most bugs in application code don’t come from adding two numbers. They come from code that reaches outside itself: network requests, files, plugin APIs, timers, IPC channels, storage layers.

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

マイクロサービスアーキテクチャを示す白板図。API、データストア、外部サービス、イベントドライブデータフローを含みます。

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

保守可能なテストのガイドラインは 単一の行動範囲のカバレッジ そして、テストごとに1つの強力なアサーション そして、また、モックを過度に使用すると、テストが実装の詳細に密接に結びつき、脆弱になることを警告しています。これは、保守可能なユニットテストに関するTestRailの記事 その警告は、JavaScriptで非常に重要です。チームは、すべてのインポートされたモジュールをモックすることで始め、実際の行動をテストするのではなく、関数が他の関数を「正しく」呼び出すかどうかをテストするのではなく、.

モックが多すぎるテストの悪い目標:

ヘルパーAがヘルパーBを呼び出しているかどうか

  • whether helper A called helper 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にもそのパターンが機能します。ネイティブAPIやプラットフォームAPIのラッパー層を用意し、ユニットテストはサービス層をモックするのではなく、直接ランタイムをモックしないようにします。 ipcRendererファイルアクセスやシェル統合を、薄いアダプタ層の後ろに隠すことができます。ユニットテストはサービス層をモックするのではなく、直接ランタイムをモックしないようにします。

リリースロジックやアップデートパスをテストするチーム向けに、CapacitorアプリではCapgoが関連するガイドを提供しています。 テスト Capacitor OTA の更新をシナリオモックでテストする.

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

非同期フローを不安定さなくテストする

テストで使用する async/await テストで使用する場合、テスト対象の code がプロミスを返す場合。コールバック重視のパターンよりも明確で、デバッグも容易です。

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');
});

ハッピーパスとアグリーパスを両方テストする。実用的なアプリケーションでは、アグリーパスはユーザーが思い出すパスです。

堅牢なテストの高度な戦略

テストスイートは、code が変更された後でも有用なままになることが重要です。単にパスするテストを大量に書くことよりも難しいです。

堅牢なソフトウェアを構築し、維持可能なテストスイートを構築するための戦略を示す図

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

実用的なガイドでは、 70/20/10 分割 単体、統合、エンドツーエンドのテスト,単体テストは最速のフィードバックと最も安定したエラーを提供します。同様のガイドは、単体テストの完全なセットが理想的には10秒以内に完了し、pre-commitチェックは5秒以内に完了することを示しています。このOpenReplayテストガイドを参照してください。 私はそれを予算ツールとしてではなく、宗教として捉えていません。エンドツーエンドテストに多くの努力を費やすと、チームはフィードバックを長く待つことになります。単体テストのみに焦点を当てると、システムの実際の境界を無視することになります。CapgoまたはElectronアプリの場合、健康的なバランスは通常以下のようになります。 単体テスト価格ロジック、パーミッションルール、シリアライゼーション、更新の有効性、機能フラグ、状態変換 For a __CAPGO_KEEP_0__ or Electron app, a healthy balance usually looks like this: Unit tests for pricing logic, permissions rules, serialization, update eligibility, feature flags, and state transforms.

For a __CAPGO_KEEP_0__ or Electron app, a healthy balance usually looks like this: Unit tests for pricing logic, permissions rules, serialization, update eligibility, feature flags, and state transforms

For a Capacitor or Electron app, a healthy balance usually looks like this: Unit tests for pricing logic, permissions rules, serialization, update eligibility, feature flags, and state transforms

  • For a __CAPGO_KEEP_0__ or Electron app, a healthy balance usually looks like this: Unit tests for pricing logic, permissions rules, serialization, update eligibility, feature flags, and state transforms For a __CAPGO_KEEP_0__ or Electron app, a healthy balance usually looks like this: Unit tests for pricing logic, permissions rules, serialization, update eligibility, feature flags, and state transforms
  • 統合テスト ストレージアダプタ、プラグインラッパー、IPCコントラクトのためのテスト
  • エンドツーエンドテスト 重要なロジックの未テストのbranchを発見するのに役立つ場合、カバレッジレポートは有用です。チームがカバレッジパーセントを追求するためにカバレッジを求める場合、有害になります。

UIのバリデーションが重視されているチームが品質を高める際に、このガイド

フロントエンドフォームバリデーションをマスターする

A login validator with thoughtful edge-case tests gives more value than a covered file full of trivial assertions. That’s especially true for input-heavy code such as forms, parsers, date logic, and permission checks. If your team is tightening quality around validation-heavy UI, this guide on ビヘイビアファーストテストはリファクタリングに耐える リリース後のリファクタリングでテストを書き直す必要がなくなるようにするには、観察可能な動作をアサートするのが一番簡単です。

__CAPGO_KEEP_0__

入力が多い__CAPGO_KEEP_0__ 入力が多いフォーム、パーサー、日付ロジック、許可チェック 実装詳細ではなく。

長期に持続する用例:

  • 境界条件 空の入力、null値、無効な型、オーバーサイズの文字列など
  • ドメインの結果 例えば「権限が欠如しているため返却が拒否される」
  • 状態の移行 例えば「ダウンロードメタデータが検証された後、更新を保留状態にする」

長期に持続しない用例:

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

For app teams building disciplined release processes, Capgo’s article on アプリの品質保証 は、テスト作業をより広いリリースパイプラインと結びつけることで、有用である。

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

1人の開発者のマシン上で実行されるテストだけでは、安全性の網にはならない。ローカルな習慣にしかならない。

CIは、ユニットテストのJavaScript作業をチームのインフラに変える。毎回のプッシュ、プルリクエスト、リリースブランチは、同じコマンドと同じ期待値で同じコマンドを実行できる。そうした一貫性は、環境の変化が微妙なエラーを引き起こすElectronプロジェクトやCapacitorプロジェクトにとって、もっとも重要である。

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

CIは、最低限、依存関係をインストールし、ユニットスイートを毎回の変更セットで実行する必要がある。可能な限り、ローカル開発と同じコマンドを使用すること。

GitHubアクションズワークフローの基本的なものは、以下のようになる。

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アプリのCI/CD設定の実用ガイド.

プラグインのCapacitorのテスト

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.

__CAPGO_KEEP_0__のプラグインの呼び出しをアダプターに残すことの良いパターンは、薄い抽象化です。

// 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 });
});

カメラのアクセス、バイオメトリックのプロンプト、プッシュトークンの登録、ネットワークのステータスも同じ考え方を適用します。

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

Electronアプリには2つの重要なシームがあります。 code そして codeテストではこれらを曖昧にしないでください。

信頼できるセットアップでは通常、

  • レンダラーのユニットテスト ビューモデル、状態、フォーマット、UI側のビジネスロジック用
  • メインプロセスユニットテスト メニュー、ファイル操作、Appライフサイクル決定用
  • 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単体テストについてよくある質問

単体統合テストとE2Eテストの違いは何ですか

A 単体テスト 1つの小さなロジックの単体テストです。 統合テスト 一部のコンポーネントやサービスが正しく動作するかどうかを確認する。 エンドツーエンドテスト 実行中のアプリケーションを通してユーザーのジャーニーを実行する。

ビジネスルールの迅速な信頼性のためにユニットテストを使用します。統合テストを使用して、ストレージ、プラグインラッパー、IPCなどのシームを使用します。E2Eテストは、破壊される可能性のあるワークフローに限って、慎重に使用してください。

完全なカバレッジを目指すべきか

いいえ。完全なカバレッジは、チームを低価値のテストに導く可能性があります。

カバレッジは、誰も実行していないリスクのあるcodeを明らかにするときに役立ちますが、エンジニアがダッシュボードを満たすために浅いアサーションを追加するときに役立ちません。もしもスイートが脆弱であれば、カバレッジが増えてもそれを救うことはできません。

既存のコードベースにテストを追加するにはどうしたらいいか

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

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

  • アクティブなcodeを保護することから始めましょう 機能開発やバグ修正の際に触れるモジュールにテストを追加することで
  • __CAPGO_KEEP_0__ 難テストファイルから純粋なロジックを抽出する
  • フレームワークや実行環境のノイズを排除してビジネスルールをテストできるようにする ネイティブプラグイン、ネットワーククライアント、ファイルシステム呼び出し、Electron IPC周りのシームワッパーを追加する
  • モックを導入する際に脆弱なパターンを拒否する JavaScriptテストベストプラクティス 特に、オーバーモッキングとその結果となる脆弱なテストをよく見落とす問題を強調することで、ここでは特に有用である 目標は即時的な完全性ではなく、チームにとって最もコストがかかる場所での段階的な改善である

チームが


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

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

ウェブ層のバグが実行中の場合、Capgoを使用して修正を配信するのではなく、数日間待ってアプリストアの承認を待つのではなく、ユーザーはバックグラウンドで更新を受け取り、ネイティブの変更は通常のレビュー経路に残る。

スタートする

最新のブログ記事

Capgoは、プロフェッショナルなモバイルアプリを作成するために必要な最良の洞察を提供します。