web-dev-qa-db-ja.com

テストしたいReactコンポーネント内にカスタムフックをモックする方法は?

データをフェッチするカスタムフックを呼び出すReactコンポーネントがある場合、Reactコンポーネントをテストするときにその内部カスタムフック結果を模擬する最良の方法は何ですか?私は2つの主要なアプローチを見ます:

1)カスタムフックをJest.mockします。これは最も推奨されるアプローチのようですが、コンポーネントのpropsインターフェースが提案するもの(prop-typesまたはTypeScript)

2)依存性注入アプローチを使用します。フックを小道具として宣言しますが、デフォルトで実際のフックに設定するので、コンポーネントをレンダリングするすべての場所で設定する必要はありませんが、テスト用にモックでオーバーライドできます。カスタムフックを模倣するテストを含む、コードサンドボックスの例を以下に示します。

https://codesandbox.io/s/dependency-inject-custom-hook-for-testing-mjqlf?fontsize=14&module=%2Fsrc%2FApp.js

2はより多くのタイピングを必要としますが、テストのために操作する方が簡単なようです。ただし、テストでは、レンダリングされた出力の条件付きロジックをテストするために、コンポーネントの内部実装の詳細を知っている必要があるため、それは重要ではなく、1が最善のアプローチです。 1は行く方法ですか?どのようなトレードオフが見られますか?完全に別のアプローチが欠けていますか?

9
sschottler

この質問は数か月前のものですが、適切な解決策が見つからない場合は、役立つパッケージを作成しました。 「フックをコンポーネントに挿入するとどうなるか」など、同様の思考プロセスを経ました。物事が変になりました。

私は基本的に、それらをテストするためだけにプレゼンテーションコンポーネントの追加のラッパーを回避するためのコネクタを望んでいました。

私はreact-hooks-composeを思いついたので、フックとプレゼンターを別々にして、個別にまたは一緒にテストできます。 https://www.npmjs.com/package/react-hooks-compose

export const useFetch = () => {
  const [user, setUser] = useState();

  useEffect(() => {
    fetchData('some-url') // <-- Fetches data on mount
      .then(res => setUser(res.data));
  }, []);

  return {user};
}

// composeHooks passes the values from your hooks as props
export const UserPresenter = ({user}) => {
  return <div>You fetched data for: {user.name}</div>;
}

export default composeHooks({ useFetch })(DataPresenter);

これでフックを模擬する必要がなくなり、プレゼンターを小道具でテストできます。

it('presents user', () => {
  const { queryByText } = render(<UserPresenter user={{name: 'Mary'}} />); // <-- Named export
  expect(queryByText('Mary')).toBeTruthy();
});

または、より高いレベルの統合テストのオプションがあります。

it('fetches data', () => {
  fetchData.mockResolvedValue('Mary');
  const { queryByText } = render(<UserWithData />); // <-- Default export
  expect(queryByText('Mary')).toBeFalsy();
  return wait(() => {
    expect(queryByText('Mary')).toBeTruthy();
  });
});

必要に応じて、フックを単体テストすることもできます。

1
helloitsjoe

代わりに、API呼び出しを行う基になるメソッドをモックしてみませんか?

たとえば、fetch()を使用してデータを取得する場合は、代わりにそれをモックします。これにより、その呼び出しのカスタム応答を定義できるため、フック自体のテストが容易になります。

1
Clarity

モックフック自体を使用すると、実際のコンポーネントがコンポーネントと完全にうまく機能するかどうかはわかりません。

フックを小道具として渡すと、フックが互いに通信することは本当に難しいでしょう。例えば。同じコンポーネントuseStateからセッターを呼び出すカスタムフックが必要な場合。より多くのパラメーターでカスタムフックを拡張する必要があります。

  1. 外部API呼び出しをモックすることもできます-fetchまたはXHRをモックすることを意味します。それでも、いくつかの実装の詳細(HTTPリクエストを実行しているという事実)を知る必要がありますが、テストについて知っておくべきことが少なくなります。
0
skyboyer