スナップショットテストの問題

Jestによって普及されたスナップショットテストは、意味があるときにアプリをテストするのに役立つ素晴らしいツールです。しかし、おそらくその強力さのために、開発者によって過剰に使用されることがよくあります。この件に関しては、すでに複数の記事があります。この特定のケースでは、スナップショットテストが開発者の意図を反映できていません。別の情報を見ないと、アサーションが何についてのものであるかは明確ではありません。これにより、コードの理解が難しくなり、書いた人以外の他の読者にとって精神的な負担が生じます。読者として、私たちはそれらを完全に理解するためにコードを行き来しなければなりません。コードの複雑さが増すことで、貢献者が自分のニーズに合わせてテストを変更することをためらわせます。時には、著者を混乱させ、誤って間違ったスナップショットをコミットすることさえあります。

ここに、テストタイトルとコメントを追加した同じテストがあります。これで、これらのアサーションが実際に何についてのものであるかがわかります。

  1. it( 'can be split at the end', async () => {
  2. // ...
  3. // Expect empty paragraph outside quote block.
  4. expect( await getEditedPostContent() ).toMatchSnapshot();
  5. // ...
  6. // Expect the paragraph to be merged into the quote block.
  7. expect( await getEditedPostContent() ).toMatchSnapshot();
  8. } );

開発者の意図は少し読みやすくなっていますが、テストからはまだ切り離されているように感じます。インラインスナップショットを試してみたくなるかもしれませんが、これはファイルを行き来する必要がある問題を解決しますが、依然として自己文書化されておらず明示的ではありません。私たちはもっと良いことができます。

解決策

アサーションをコメントとして書く代わりに、直接明示的に書くことを試みることができます。editor.getBlocksの助けを借りて、これらをよりシンプルで原子的なアサーションに書き直すことができます。

  1. // ...
  2. // Expect empty paragraph outside quote block.
  3. await expect.poll( editor.getBlocks ).toMatchObject( [
  4. {
  5. name: 'core/quote',
  6. innerBlocks: [
  7. {
  8. name: 'core/paragraph',
  9. attributes: { content: '1' },
  10. },
  11. ],
  12. },
  13. {
  14. name: 'core/paragraph',
  15. attributes: { content: '' },
  16. }
  17. ] );
  18. // ...
  19. // Expect the paragraph to be merged into the quote block.
  20. await expect.poll( editor.getBlocks ).toMatchObject( [ {
  21. name: 'core/quote',
  22. innerBlocks: [
  23. {
  24. name: 'core/paragraph',
  25. attributes: { content: '1' },
  26. },
  27. {
  28. name: 'core/paragraph',
  29. attributes: { content: '2' },
  30. },
  31. ],
  32. } ] );

これらのアサーションはより読みやすく、明示的です。追加のアサーションを加えたり、既存のアサーションを複数に分割してその重要性を強調することができます。コメントを保持するかどうかはあなた次第ですが、コードがすでに読みやすい場合は、通常は省略しても問題ありません。

スナップショットのバリアント

Playwrightにインラインスナップショットがないため、一部の移行されたテストは、文字列アサーション(toBe)を使用して、数十のスナップショットファイルを作成することなく類似の効果をシミュレートしています。

  1. expect( await editor.getEditedPostContent() ).toBe( `<!-- wp:paragraph -->
  2. <p>Paragraph</p>
  3. <!-- /wp:paragraph -->` );

このパターンをスナップショットテストのバリアントと見なすことができ、これらを書くときは同じルールに従うべきです。editor.getBlocksや他の方法を使用して、明示的なアサーションに書き直す方がしばしば良いです。

  1. await expect.poll( editor.getBlocks ).toMatchObject( [ {
  2. name: 'core/paragraph',
  3. attributes: { content: 'Paragraph' },
  4. } ] );

テストカバレッジはどうなる?

明示的なアサーションとスナップショットテストを比較すると、このテストでは確実にいくつかのテストカバレッジを失っています。スナップショットテストは、ブロックの完全なシリアライズされたコンテンツを主張したいときにまだ有用です。しかし幸運なことに、統合テストのいくつかは、各コアブロックの完全なコンテンツをすでに主張しています。これらはNode.jsで実行されるため、Playwrightで同じテストを繰り返すよりもはるかに速くなります。私のマシンで273のテストケースを実行するのに約5.7秒しかかかりません。この種のテストはユニットまたは統合レベルでうまく機能し、テストカバレッジを失うことなく、はるかに速く実行できます。

ベストプラクティス

スナップショットテストはE2Eテストではほとんど必要とされることはなく、明示的なアサーションを活用するより良い代替手段がしばしばあります。他に適切な代替手段がない場合には、使用時のベストプラクティスに従うべきです。

巨大なスナップショットを避ける

巨大なスナップショットは読みづらく、レビューが難しいです。さらに、すべてが重要である場合、何も重要ではありません。巨大なスナップショットは、スナップショットの重要な部分に集中することを妨げます。

繰り返しのスナップショットを避ける

同じテストで似たような内容の複数のスナップショットを作成している場合、それはおそらくより原子的なアサーションを作成したいというサインです。何をテストしたいのかを再考してください。最初のスナップショットが2番目のスナップショットの参照に過ぎない場合、あなたが望んでいるのはスナップショット間の違いである可能性が高いです。最初の結果を変数に保存し、結果間の違いを主張してください。

さらなる読み物