目次
反応テストを開始します
オプション1:ユニットテスト
オプション2:統合テスト
それで、単体テストに何が必要ですか?
その他の利点
ブロックをクリアします
インラインITコメント
チームの次のステップ
ホームページ ウェブフロントエンド CSSチュートリアル 反応統合テスト:カバレッジが増え、テストが少なくなります

反応統合テスト:カバレッジが増え、テストが少なくなります

Apr 07, 2025 am 09:20 AM

反応統合テスト:カバレッジが増え、テストが少なくなります

Reactで構築されたようなインタラクティブなWebサイトの場合、統合テストは自然な選択です。エンドツーエンドテストの追加オーバーヘッドなしで、ユーザーがアプリケーションと対話する方法を検証します。

この記事では、単純なWebサイトから始まり、単体テストと統合テストを使用して動作を検証するエクササイズで説明し、統合テストがコード行の少ない価値をより大きく達成する方法を示します。この記事では、ReactとJavaScriptでのテストに精通していると想定しています。 JestおよびReact Testingライブラリに精通することは役立ちますが、必要ありません。

テストには3つのタイプがあります。

  • ユニットテストは、コードの一部を独立して検証します。彼らは簡単に書くことができますが、全体像を無視するかもしれません。
  • エンドツーエンドテスト(E2E)サイプレスやセレンなどの自動フレームワークを使用して、ユーザーなどのWebサイトと対話します。ページのロード、フォームの記入、ボタンのクリックなど。それらは通常、ゆっくりと書かれて実行されますが、実際のユーザーエクスペリエンスに非常に近いです。
  • 統合テストはその間のどこかにあります。アプリケーションの複数のユニットがどのように連携するかを確認しますが、E2Eテストよりも軽いです。たとえば、Jestには、統合テストを容易にするためのいくつかの組み込みユーティリティが付属しています。 Jestは、バックグラウンドでJSDOMを使用して、自動化よりもオーバーヘッドが少ない一般的なブラウザAPIをシミュレートし、その強力なモッキングツールは外部API呼び出しをシミュレートできます。

別の注意事項:Reactアプリケーションでは、単体テストと統合テストが同じ方法で記述され、ツールが使用されます

反応テストを開始します

ログインフォームを使用して、Simple Reactアプリケーション(GitHubで利用可能)を作成しました。私はそれをreqres.inに接続します。これは、フロントエンドプロジェクトのテストに使用することがわかった便利なAPIです。

正常にログインできます。

...またはAPIからのエラーメッセージが発生します。

コード構造は次のとおりです。

 <code>LoginModule/ ├── components/ │ ├── Login.js // 渲染LoginForm、错误消息和登录确认│ └── LoginForm.js // 渲染登录表单字段和按钮├── hooks/ │ └── useLogin.js // 连接到API 并管理状态└── index.js // 将所有内容整合在一起</code>
ログイン後にコピー

オプション1:ユニットテスト

私のようなテストを書くのが好きなら(ヘッドフォンを着て、Spotifyで素敵な音楽を演奏することもあれば、各ファイルの単位テストを書くことに抵抗できないかもしれません。

テスト愛好家でなくても、明確な戦略なしで「テストの良い仕事をしようとする」プロジェクトに取り組んでいる可能性があり、テスト方法は「すべてのファイルに独自のテストが必要だと思いますか?」

これは次のように見えます(明確にするためにテストファイル名にユニットを追加しました):

 <code>LoginModule/ ├── components/ │  ├── Login.js │  ├── Login.unit.test.js │  ├── LoginForm.js │  └── LoginForm.unit.test.js ├── hooks/ │  ├── useLogin.js │  └── useLogin.unit.test.js ├── index.js └── index.unit.test.js</code>
ログイン後にコピー

GitHubでエクササイズを完了してこれらすべてのユニットテストを追加し、テストを作成しました:カバレッジ:カバレッジレポートを生成するユニットスクリプト(JESTの組み込み機能)。 4つのユニットテストファイルを使用して、100%のカバレッジを達成できます。

通常、100%のカバレッジは圧倒的ですが、このような単純なコードベースでは可能です。

Onlogin Reactフック用に作成された単体テストの1つを掘り下げましょう。 Reactフックやテスト方法に慣れていない場合は、心配しないでください。

テスト( '成功したログインフロー'、async()=> {
 //成功したAPI応答Jestをシミュレートします
  .spyon(window、 'fetch')
  .MOCKRESOLVEDVALUE({json:()=>({token: '123'})});

 const {result、waitfornextupdate} = renderhook(()=> uselogin());

 act(()=> {
  result.current.Onsubmit({
   電子メール: '[電子メール保護]'、
   パスワード:「パスワード」、
  });
 });

 //ステータスを保留中に設定します
 expect(result.current.state).toequal({
  ステータス:「保留中」、
  ユーザー:null、
  エラー:null、
 });

 waitfornextupdate()を待ちます。

 //ステータスを解決に設定してメールアドレスを保存します
  ステータス:「解決済み」、
  ユーザー:{
   電子メール: '[電子メール保護]'、
  }、
  エラー:null、
 });
});
ログイン後にコピー

このテストは、React Hooks Testing Libraryがテストフックを簡単にするため)に書くのが興味深いですが、いくつかの問題があります。

まず、テスト検証内部状態は「保留中」から「解決」に変更されます。この実装の詳細はユーザーにさらされていないため、テストするのは良いことではないかもしれません。アプリケーションをリファクタリングする場合、ユーザーの観点から何も変わらなくても、このテストを更新する必要があります。

また、単体テストとして、これはその一部にすぎません。送信ボタンテキストを「読み込み」に変更するなど、ログインプロセスの他の機能を確認する場合は、別のテストファイルで実行する必要があります。

オプション2:統合テスト

このプロセスを検証するために、統合テストに代わるものを追加することを考えてみましょう。

 <code>LoginModule/ ├── components/ │  ├── Login.js │  └── LoginForm.js ├── hooks/ │  └── useLogin.js ├── index.js └── index.integration.test.js</code>
ログイン後にコピー

このテストとテスト:カバレッジ:統合スクリプトを実装して、カバレッジレポートを生成しました。ユニットテストと同様に、100%のカバレッジに達することができますが、今回はすべて1つのファイルにあり、コードの行が少なくなります。

成功したログインプロセスをカバーする統合テストは次のとおりです。

 test( '成功ログイン'、async()=> {
  冗談
    .spyon(window、 'fetch')
    .MOCKRESOLVEDVALUE({json:()=>({token: '123'})});

  与える(<loginmodule></loginmodule> );

  const emailfield = screen.getByrole( 'textbox'、{name: 'email'});
  const passwordfield = screen.getByLabelText( 'password');
  const button = screen.getByrole( 'Button');

  // fireevent.change(emailfield、{target:{value: '[email protected]'}});
  fireevent.change(passwordfield、{target:{value: 'password'}});
  fireevent.click(ボタン);

  // Load State expect(button).tobedisabled()を設定します。
  expect(button).tohaveTextContent( 'Loading ...');

  待機中(()=> {
    // form element expect(button).not.tobeinthedocument();
    expect(emailfield).not.tobeinthedocument();
    expect(passwordfield).not.tobeinthedocument();

    //成功テキストとメールアドレスconst loggedintext = screen.getByText( 'ログインas');
    expect(loggedintext).tobeinthedocument();
    const emailaddresstext = screen.getByText( '[電子メール保護]');
    expect(emailaddresstext).tobeinthedocument();
  });
});
ログイン後にコピー

このテストは、ユーザーの観点からログインプロセス全体を検証するため、フォーム、ロードステータス、および成功した確認メッセージを検証するため、私は本当に気に入っています。統合テストは、正確にはこのユースケースのために、Reactアプリケーションに最適です。ユーザーエクスペリエンスは私たちがテストしたいものであり、これにはほとんどの場合、一緒に動作するコードの複数の異なるスニペットが含まれます。

このテストは、予想される動作を機能させるコンポーネントまたはフックを理解していません。これは素晴らしいことです。ユーザーエクスペリエンスが同じままである限り、テストを破ることなく、これらの実装の詳細を書き換えてリファクタリングすることができます。

エラー処理のためにログインプロセスの初期状態やその他の統合テストを掘り下げることはありませんが、GitHubで表示することをお勧めします。

それで、単体テストに何が必要ですか?

ユニットテストと統合テストを検討するのではなく、一歩後退して、そもそもテストする必要があるものをどのように決定するかを考えてみましょう。 LoginModuleは、ユーザー(アプリケーションの他のファイル)に自信を持って使用できるようにしたいエンティティであるため、テストする必要があります。

一方、LoginModuleの実装の詳細だけであるため、Onloginフックをテストする必要はありません。ただし、要件が変更され、Onloginが他の場所に使用ケースがある場合は、独自の(ユニット)テストを追加して、その機能を再利用可能なユーティリティとして検証する必要があります。 (ファイルもログインモジュールに固有ではないため、ファイルを移動する必要があります。)

単体テストには、再利用可能なセレクター、フック、通常の機能を検証する必要性など、まだ多くのユースケースがあります。コードを開発するときは、後で統合テストにそのロジックを移動しても、単体テスト駆動型開発を使用することも役立つ場合があります。

さらに、ユニットテストは、複数の入力とユースケースの徹底的なテストの素晴らしい仕事をします。たとえば、私のフォームがさまざまなシナリオのインライン検証を表示する必要がある場合(たとえば、無効な電子メール、パスワードが欠けている、パスワードが短すぎる)、統合テストで代表的なケースをカバーし、単体テストで特定のケースを掘り下げます。

その他の利点

私たちがここにいるので、統合テストを明確で整然と保つのに役立ついくつかの構文のヒントについてお話したいと思います。

ブロックをクリアします

私たちのテストでは、荷重状態とログインモジュールの成功状態の間の遅延を考慮する必要があります。

 const button = screen.getByrole( 'Button');
fireevent.click(ボタン);

expect(button).not.tobeinthedocument(); //速すぎると、ボタンはまだそこにあります!
ログイン後にコピー

DOMテストライブラリのWaitfor Helper機能を使用してこれを行うことができます。

 const button = screen.getByrole( 'Button');
fireevent.click(ボタン);

待機中(()=> {
 expect(button).not.tobeinthedocument(); //ああ、それははるかに優れています});
ログイン後にコピー

しかし、他のプロジェクトをテストしたい場合はどうなりますか?これをどのように処理するかについてインターネット上には多くの良い例はありません。過去のプロジェクトでは、他のプロジェクトをWaitfor以外に置きました。

 //待機ボタンを待ってくださいwaitfor(()=> {
 expect(button).not.tobeinthedocument();
});

//次に、確認メッセージconst confirmentationtext = getByText( '[電子メール保護]');
expect(cusmentationtext).tobeinthedocument();
ログイン後にコピー

これは機能しますが、これらのステートメントの順序を簡単に切り替えることができても、ボタン状態を特別に見せるため、私はそれが好きではありません。

 //確認メッセージが待機するのを待ってくださいwaitfor(()=> {
 const cundimationText = getByText( '[電子メール保護]')としてログインします ');
 expect(cusmentationtext).tobeinthedocument();
});

// [ボタン] [ボタン).not.tobeinthedocument()をテストします。
ログイン後にコピー

同じアップデートに関連するすべてをWaitfor Callbackにグループ化する方がはるかに良いように思えます。

待機中(()=> {
 expect(button).not.tobeinthedocument();

 const cundimationText = screen.getByText( '[電子メール保護]')としてログインします ');
 expect(cusmentationtext).tobeinthedocument();
});
ログイン後にコピー

私はこのような単純な主張のためのこの手法が本当に好きですが、場合によってはテストを遅くすることができ、Waitforのすぐ外で発生する失敗を待っています。この例については、React Testing Libraryの共通エラーの「コールバックの1回の待機中の複数のアサーション」を参照してください。

いくつかのステップを含むテストの場合、複数の待機を連続して使用できます。

 const button = screen.getByrole( 'Button');
const emailfield = screen.getByrole( 'textbox'、{name: 'email'});

// fireevent.change(emailfield、{target:{value: '[email protected]'}})のフォームに記入します。

待機中(()=> {
 //ボタンが有効になっているかどうかを確認する(ボタン).not.tobedisabled();
  expect(button).tohavetextcontent( 'submit');
});

// fireevent.click(button);

待機中(()=> {
 //ボタンが存在しなくなったかどうかを確認します(ボタン).not.tobeinthedocument();
});
ログイン後にコピー

アイテムが1つだけ表示されるのを待っている場合は、代わりにFindByクエリを使用できます。バックグラウンドでWaitforを使用します。

インラインITコメント

別のテストベストプラクティスは、より少ない、より長いテストを書くことです。これにより、テストケースを重要なユーザープロセスと相関させることができ、予期しない動作を避けるためにテストを隔離し続けることができます。私はこのアプローチに同意しますが、コードを整理し、必要な動作を文書化することに課題をもたらす可能性があります。将来の開発者がテストに戻り、それが何をしているのか、なぜ失敗するのかを理解できるようにする必要があります。

たとえば、これらの期待の1つが失敗し始めたとします。

それ( '成功したログインフローを処理します'、async()=> {
 //明確にするためにテストの開始を非表示にします

  (ボタン).tobedisabled();
  expect(button).tohaveTextContent( 'Loading ...');


 待機中(()=> {
  expect(button).not.tobeinthedocument();
  expect(emailfield).not.tobeinthedocument();
  expect(passwordfield).not.tobeinthedocument();


  const cundimationText = screen.getByText( '[電子メール保護]')としてログインします ');
  expect(cusmentationtext).tobeinthedocument();
 });
});
ログイン後にコピー

このコンテンツを見る開発者は、テストされているものを簡単に判断できず、障害がバグ(コードを修正する必要があることを意味する)か、動作の変更(テストを修正する必要があることを意味します)であるかどうかを判断するのが難しい場合があります。

私のお気に入りのソリューションは、テストごとにあまり知られていないテスト構文を使用し、テストされている各重要な動作を説明するインラインスタイルのコメントを追加することです。

 test( '成功ログイン'、async()=> {
 //明確にするためにテストの開始を非表示にします

 //ロードステータスexpect(button).tobedisabled()を設定します。
  expect(button).tohaveTextContent( 'Loading ...');


 待機中(()=> {
  // form element expect(button).not.tobeinthedocument();
  expect(emailfield).not.tobeinthedocument();
  expect(passwordfield).not.tobeinthedocument();


  //成功テキストと電子メールアドレスconst confirmentationtext = screen.getByText( '[電子メール保護]');
  expect(cusmentationtext).tobeinthedocument();
 });
});
ログイン後にコピー

これらのコメントは魔法のようにJESTと統合されていないため、障害が発生した場合、テスト名の失敗はテストタグに渡されたパラメーター、この場合は「ログインの成功」に対応します。ただし、Jestのエラーメッセージには周囲のコードが含まれているため、これらのITコメントは依然として失敗した動作を識別するのに役立ちます。期待から削除しないと、次のエラーメッセージが表示されます。

より明示的なエラーを取得するために、各期待のエラーメッセージを定義できるJest-Expect-Messageというパッケージがあります。

想像(ボタン、 'ボタンはまだドキュメントにあります')。
ログイン後にコピー

一部の開発者はこのアプローチを好みますが、ほとんどの場合、私はそれが少しきめになりすぎていると思います。単一は通常、複数の期待を伴うためです。

チームの次のステップ

時々、私たちは人間のためにリナールールを作ることができたらいいのにと思います。もしそうなら、私たちはチームに優先統合テストルールを設定することができ、それは終わります。

しかし、残念ながら、以前に紹介したログインモジュールの例など、場合によっては開発者が統合テストを選択することを奨励するために、より類似したソリューションを見つける必要があります。ほとんどのことと同様に、それはあなたのテスト戦略について議論し、プロジェクトにとって何が理にかなっていることに同意し、そしてそれをADRで説明するチームに帰着します。

テスト計画を開発するときは、開発者が各ファイルのテストを作成するように強制する文化を避ける必要があります。開発者は、「アンダーテスト」を心配することなく、情報に基づいたテストの決定を自信を持って行うことができる必要があります。 Jestのカバレッジレポートは、テストが統合レベルでマージされたとしても、正気チェックを提供することにより、この問題を解決するのに役立ちます。

私はまだ自分自身を統合テストの専門家とは考えていませんが、この演習を行うと、統合テストがユニットテストよりも価値がある場合のユースケースを分解するのに役立ちました。これをチームと共有するか、コードベースで同様のエクササイズを行うことで、統合テストをワークフローに組み込むことができれば幸いです。

以上が反応統合テスト:カバレッジが増え、テストが少なくなりますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

静的フォームプロバイダーの比較 静的フォームプロバイダーの比較 Apr 16, 2025 am 11:20 AM

ここでは、「静的フォームプロバイダー」という用語を埋めてみましょう。あなたはあなたのHTMLを持ってきます

SASSをより速くするための概念の証明 SASSをより速くするための概念の証明 Apr 16, 2025 am 10:38 AM

新しいプロジェクトの開始時に、SASSコンピレーションは瞬く間に起こります。これは、特にbrowsersyncとペアになっている場合は素晴らしい気分です。

毎週のプラットフォームニュース:HTMLロード属性、主なARIA仕様、およびIFRAMEからShadowDOMへの移動 毎週のプラットフォームニュース:HTMLロード属性、主なARIA仕様、およびIFRAMEからShadowDOMへの移動 Apr 17, 2025 am 10:55 AM

今週のプラットフォームニュースのラウンドアップで、Chromeは、Web開発者のロード、アクセシビリティ仕様、およびBBCの動きのための新しい属性を導入します

セクション要素との取引 セクション要素との取引 Apr 12, 2025 am 11:39 AM

2つの記事がまったく同じ日に公開されました。

HTMLダイアログ要素を使用したいくつかの実践 HTMLダイアログ要素を使用したいくつかの実践 Apr 16, 2025 am 11:33 AM

これは私が初めてHTML要素を見ていることです。私はしばらくの間それを知っていましたが、まだスピンしていませんでした。かなりクールです

Google Fontsをタグ付けし、Goofonts.comを作成する方法 Google Fontsをタグ付けし、Goofonts.comを作成する方法 Apr 12, 2025 pm 12:02 PM

Goofontsは、開発者妻とデザイナーの夫によって署名されたサイドプロジェクトであり、どちらもタイポグラフィの大ファンです。 Googleにタグを付けています

マルチサムスライダー:一般的なケース マルチサムスライダー:一般的なケース Apr 12, 2025 am 10:52 AM

この2部構成のシリーズの最初の部分では、2つの親指スライダーを取得する方法を詳しく説明しました。今、私たちは&#039; llが一般的なマルチサンプスのケースを見ていますが、別のものと

「ポッドキャストにサブスクライブ」リンクはどこにすべきですか? 「ポッドキャストにサブスクライブ」リンクはどこにすべきですか? Apr 16, 2025 pm 12:04 PM

しばらくの間、iTunesはポッドキャストの大きな犬だったので、「ポッドキャストにサブスクライブ」をリンクした場合:

See all articles