Jest 14.0: Reactツリースナップショットテスト
このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →
Jestの哲学の一つは、統合された「ゼロ設定」体験を提供することです。有用なテストを書く際の摩擦を可能な限り減らし、エンジニアがすぐに使えるツールを提供することで、より多くのテストが書かれ、結果として安定した健全なコードベースが生まれることを目指 しています。
大きな未解決課題の一つは、効率的にReactテストを書く方法でした。ReactTestUtilsやenzymeなど多くのツールが存在します。これらは優れたツールで広く使われています。しかしエンジニアからは「コンポーネント自体よりもテストを書くのに時間がかかる」という声が頻繁に寄せられました。その結果、多くの人がテスト作成を完全に止めてしまい、最終的に不安定なコードにつながりました。エンジニアたちが本当に求めていたのは、コンポーネントが予期せず変更されないことを保証する方法でした。
Reactチームと共同で、新しいReact用テストレンダラーを開発し、Jestにスナップショットテスト機能を追加しました。シンプルなLinkコンポーネントのテスト例をご覧ください:
import renderer from 'react-test-renderer';
test('Link renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.facebook.com">Facebook</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});
このテストが初めて実行されると、Jestは次のようなスナップショットファイルを作成します:
exports[`Link renders correctly 1`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function bound _onMouseEnter]}
onMouseLeave={[Function bound _onMouseLeave]}>
Facebook
</a>
`;
スナップショット成果物はコード変更と共にコミットする必要があります。コードレビュー時にスナップショットを人間が読みやすい形式にするため、pretty-formatを使用しています。以降のテスト実行では、Jestがレンダリング結果を前回のスナップショットと比較します。一致すればテストは成功、不一致の場合は実装が変更されたためjest -uでスナップショットを更新する必要があるか、テストランナーが修正すべきバグを検出したかのいずれかです。
例のLinkコンポーネントが指すアドレスを変更すると、Jestは次の出力を表示します:

変更を受け入れるにはjest -uを実行し、意図しない変更の場合はコンポーネントを修正します。この機能を試すには、スナップショットの例をクローンし、Linkコンポーネントを変更してJestを実行してください。Reactチュートリアルもスナップショットテストのガイドで更新しました。
この機能はBen AlpertとCristian Carlessoによって開発されました。
実験的React Nativeサポート
特定プラットフォームを対象としないテストレンダラーを構築したことで、ついに完全なモックなしバージョンのReact Nativeをサポートできるようになりました。jest-react-nativeパッケージを通じて、Jestの実験的React Nativeサポートを開始できることを嬉しく思います。
React NativeでJestを使い始めるには、yarn add --dev jest-react-nativeを実行し、Jest設定にプリセットを追加します:
"jest": {
"preset": "jest-react-native"
}
-
人気のReact Nativeオープンソースライブラリ_snowflake_へのプルリクエスト例
現在のプリセットは、React Nativeテストを始めるのに必要な最小限の設定のみを実装しています。コミュニティの貢献によるプロジェクト改善を期待しています。ぜひお試しいただき、issuesを報告したりプルリクエストを送ってください!
なぜスナップショットテストなのか?
Facebookのネイティブアプリでは「スナップショットテスト」と呼ばれるシステムを使用しています:UIコンポーネントをレンダリングし、スクリーンショットを取得し、記録されたスクリーンショットとエンジニアによる変更を比較するテストシステムです。スクリーンショットが一致しない場合、予期せぬ変更が発生したか、UIコンポーネントの新しいバージョンにスクリーンショットを更新する必要があるかのどちらかです。
これがWeb向けに求めていた解決策でしたが、このようなエンドツーエンドテストにはスナップショット統合テストが解決する多くの問題があることもわかりました:
-
不安定性がない: テストが実ブラウザや実機ではなくコマンドラインランナーで実行されるため、ビルド待ち・ブラウザ起動・ページ読み込み・UI操作によるコンポーネント状態の制御といった不安定要因がなく、テスト結果のノイズが軽減されます。
-
高速な反復速度: エンジニアは数分や数時間待つよりも1秒以内に結果を得たいと考えます。ほとんどのエンドツーエンドフレームワークのようにテストが高速でない場合、エンジニアはテストを実行せず、そもそも作成しようとしません。
-
デバッグの容易さ: スクリーンショットテストのシナリオを再現してビジュアル差分をデバッグする代わりに、統合テストのJavaScriptコード内で直接ステップ実行できます。
スナップショットテストがJest以外でも有用と確信しているため、この機能をjest-snapshotパッケージとして分離しました。コミュニティと協力して汎用性を高め、他のテストランナーとの統合や概念・インフラの共有を推進できることを楽しみにしています。
最後に、Facebookエンジニアがスナップショットテストでユニットテスト体験がどう変わったかを語った言葉をご紹介します:
「私のプロジェクトで最も困難だったのは、各テストケースの入力ファイルと出力ファイルを同期し続けることでした。機能の小さな変更でも出力ファイルがすべて変わってしまうのです。スナップショットテストでは出力ファイルが不要になり、スナップショットはJestが自動生成します!手動で変更する代わりに、Jestがスナップショットをどう更新するか確認するだけで済むのです」– fjs開発者のKyle Davis
Jestの今後
最近Aaron AbramovがJestチームにフルタイム参加し、Facebook広告製品向けユニットテスト・統合テストインフラの改善に取り組んでいます。今後数ヶ月でJestチームは以下の領域を重点的に強化します:
-
Jasmineの置き換え: Jasmineは開発速度を低下させており、活発にメンテナンスされてい ません。すべてのJasmineマッチャー置き換えを開始し、新機能追加とこの依存関係の削除を進めます。
-
コードカバレッジ: Jestが作成された当初はBabelのようなツールが存在しませんでした。既存のカバレッジサポートには多くのエッジケースがあり正常動作しない場合があるため、現在の課題すべてに対処するべく書き直します。
-
開発者体験: セットアッププロセスの改善、デバッグ体験の向上、CLIの改良、ドキュメント拡充など多岐にわたる改善です。
-
モッキング: モッキングシステム、特に手動モック周りは正常に動作せず混乱を招いています。より厳密で理解しやすい仕組みへ改善します。
-
パフォーマンス: 大規模コードベース特に焦点を当てたさらなるパフォーマンス改善を進めます。
ご質問がある方、協力に興味のある方は、いつでもお気軽にお問い合わせください!
