Reactコンポーネントの終了

Reactエコシステムについて私が気に入っているのは、多くのIDEASが多くの決定の背後にあるということです。 さまざまな著者が既存の順序をサポートするさまざまな記事を書いて、すべてが「正しい」理由を説明するので、誰もがパーティーが正しい軌道に乗っていることを理解しています。







しばらくして、IDEAは少し変わり、すべてが最初から始まります。







そして、この話の始まりは、コンポーネントをコンテナと非コンテナに分離することです(一般的にダムコンポーネントと呼ばれます。私のフランス語は申し訳ありません)。













問題



問題は非常に単純です-単体テスト。 最近、統合テストに向けた動きがいくつかあります- 「テストを書いてください。多すぎず、ほとんどが統合です。」 。 これは悪い考えではなく、時間が短い場合(およびテストが特に必要ない場合)、これを行う必要があります。 それを煙テストと呼びましょう-何も爆発しないように確認します。







時間がかかり、テストが必要な場合、適切な統合テストを書くのは非常に長いので、このようにしない方が良いです。 成長していくという理由だけで、右側の3番目のボタンをテストするには、メニューの3つのボタンをクリックする必要があります。ログインすることを忘れないでください。 一般的に-銀の大皿での組み合わせの爆発です。







ここでの解決策は、1つの簡単な(定義による)単体テストです。 アプリケーションの一部の既製の状態でテストを開始する機能。 より正確には、アプリケーションまたはビッグブロックからテストエリアを小さなもの(ユニットなど)に縮小(狭小化)することです。 酵素を使用する必要はありません-魂が尋ねるなら、ブラウザテストを実行できます。 ここで最も重要なことは、 単独で何かをテストできることです。 そして、あまり手間がかかりません。







分離は単体テストの重要なポイントの1つであり、それが単体テストが気に入らない理由です。 彼らはさまざまな理由でそれを好まない:









個人的には、ここで問題は発生していません。 もちろん、最初の段落では統合テストを推奨できます。統合テストは、そのために考案されたもので、事前にテストされたコンポーネントが正しく組み立てられる方法を確認します。 もちろん、アプリケーションの一部としてではなく、自分自身だけをテストするnpmパッケージを信頼します。 「コンポーネント」と「あなた以外」のパッケージとの違いは何ですか?







2番目の段落では、すべてが少し複雑です。 そして、この記事が(およびそれ以前のすべてが-はじめに)-「ユニット」 ユニットをテスト可能にする方法についてです。







分割統治



Reactコンポーネントを「コンテナ」と「プレゼンテーション」に分割するという考え方は新しいものではなく、十分に説明されており、すでに少し時代遅れになっています。 Dan Abramovの記事を基礎(開発者の99%が行うこと)にすると、プレゼンテーションコンポーネント:









コンテナはすべてロジックであり、すべてのデータへのアクセスであり、原則としてアプリケーション全体です。







理想的な世界では、コンテナはトランクであり、プレゼンテーションコンポーネントはリーフです。

ダンの定義には2つの重要なポイントがあります。それは、ほとんどが学術的な「ユニット」の定義である「アプリケーション非依存」と 、「これらの星が特に興味深い場合、他のプレゼンテーションコンポーネントとコンテナの両方を含めることができる**



」*です。







(無料翻訳)**私の記事の初期のバージョンで、私(Dan)は、プレゼンテーションコンポーネントには他のプレゼンテーションコンポーネントのみを含めるべきだと述べました。 私はもうそうは思いません。 コンポーネントのタイプは詳細であり、時間とともに変化する可能性があります。 一般に、それを共有しないでください。すべては大丈夫です。

この後何が起こるかを思い出しましょう:









問題が少し不自然だと思う場合-非コンテナで使用されるこれらのコンテナが他の部門で変更され、その結果、あなたと彼らがテストを見たときにチームとして働いてみてください。それはうまくいきました、そして今再び。

その結果、浅いものを使用する必要があります。これにより、設計上 、有害な(および予期しない)副作用がすべて排除されます。 これは記事「なぜ私はいつも浅いを使うのか」からの簡単な例です







ツールチップが「?」をレンダリングすると想像してください。クリックすると、タイプ自体が表示されます。







 import Tooltip from 'react-cool-tooltip'; const MyComponent = () => { <Tooltip> hint: {veryImportantTextYouHaveToTest} </Tooltip> }
      
      





それをテストするには? マウント+クリック+表示されているものを確認します。 これは統合テストであり、ユニットではありません。質問は、「エイリアン」コンポーネントをクリックする方法です。 浅瀬には問題がありません。 も「エイリアンコンポーネント」自体もないからです。 しかし、ツールチップはコンテナであり、MyComponentは実質的にプレゼンテーションであるため、ここには頭脳があります。







 jest.mock('react-cool-tooltip', {default: ({children}) => childlren});
      
      





ただし、react-cool-tooltipを使用すれば、テストに問題はありません。 「コンポーネント」は、非常に鈍く、はるかに短く、はるかに有限になりました







最終コンポーネント









最後のコンポーネントは、大きなメカニズムから取り出されたギアです。







全体の問題は、それをどのように取り出すかです。







解決策1-DI



私のお気に入りは依存性注入です。 ダンも彼を愛しています 。 一般に、これはDIではなく「スロット」です。 簡単に言えば、プレゼンテーション内でコンテナを使用する必要はありません-そこに注入する必要があります。 そして、テストでは、何か他のものを注入することが可能になります。







 //    mount     const PageChrome = ({children, aside}) => ( <section> <aside>{aside}</aside> {children} </section> ); //     shallow,       //     mount ? , ,   wiring? const PageChromeContainer = () => ( <PageChrome aside={<ASideContainer />}> <Page /> </PageChrome> );
      
      





これは、 「コンテナがトランクであり、プレゼンテーションコンポーネントがリーフである」場合です。







解決策2-境界



多くの場合、DIはクールです。 おそらく今、%username%は現在のコードベースにどのように適用できるかを考えており、解決策は発明されていません...







そのような場合、 Bordersはあなたを救います。







 const Boundary = ({children}) => ( process.env.NODE_ENV === 'test' ? null : children // //  jest.mock ); const PageChrome = () => ( <section> <aside><Boundary><ASideContainer /></Boundary></aside> <Boundary><Page /></Boundary> </section> );
      
      





ここでは、「スロット」の代わりに、単にすべての「移行ポイント」が境界に変わり、テスト中に何でもレンダリングします。 宣言的に十分で、まさに「ギアを取り出す」ために必要なもの。







解決策3-層



境界線は少し粗い場合があり、レイヤーに関する知識を少し追加することで、境界線を少しスマートにする方が簡単かもしれません。







 const checkTier = tier => tier === currentTier; const withTier = tier => WrapperComponent => (props) => ( (process.env.NODE_ENV !== 'test' || checkTier(tier)) && <WrapperComponent{...props} /> ); const PageChrome = () => ( <section> <aside><ASideContainer /></aside> <Page /> </section> ); const ASideContainer = withTier('UI')(...) const Page = withTier('Page')(...) const PageChromeContainer = withTier('UI')(PageChrome);
      
      





ティア/レイヤーという名前の下では、機能、アヒル、モジュール、またはそのレイヤー/ティアだけが異なることがあります。 ポイントは重要ではありません。主なことは、ギアを引くことができることです。おそらく1つではなく、最終的な数字で、必要なものと不要なものを何らかの形で線引きします(異なるテストではこれは異なる境界線です)。







そして、これらの境界を何らかの形でマークすることを妨げるものは何もありません。







解決策4-個別の懸念



解決策が(定義により)エンティティの分離にある場合-エンティティを取得して分離するとどうなりますか?







私たちがとても嫌いな「コンテナ」は、一般にコンテナと呼ばます。 そうでない場合は、今すぐにコンポーネントの名前を何とか音を立て始めます。 または、名前に特定のパターンがあります-接続(WrappedComonent)、またはGraphQL /クエリ。







実行時に、名前に基づいてエンティティ間に線を引くとどうなりますか?







 const PageChrome = () => ( <section> <aside><ASideContainer /></aside> <Page /> </section> ); // remove all components matching react-redux pattern reactRemock.mock(/Connect\(\w\)/) // all any other container reactRemock.mock(/Container/)
      
      





さらに、テストの1行、 react-remockは 、テストに干渉する可能性のあるすべてのコンテナーを削除します。







原則として、このアプローチはコンテナ自体をテストするために使用できます-最初のコンテナ以外のすべてを削除するだけです。







 import {createElement, remock} from 'react-remock'; //  "" const ContainerCondition = React.createContext(true); reactRemock.mock(/Connect\(\w\)/, (type, props, children) => ( <ContainerCondition.Consumer> { opened => ( opened ? ( // ""     <ContainerCondition.Provider value={false}> {createElement(type, props, ...children)} <ContainerCondition.Provider> ) // "" : null )} </ContainerCondition.Consumer> )
      
      





再び-いくつかのラインとギアが削除されました。







合計



過去1年間、Reactコンポーネントのテストは、特にマウントの場合、より複雑になりました。10個のプロバイダー、コンテキストすべてを上書きする必要があり、適切なスタイルで適切なコンポーネントをテストすることがますます難しくなっています。

誰かが唾を吐き、浅い世界に入ります。 誰かが単体テストで手を振って、すべてをサイプレスに転送しました(歩くような歩行!)。







他の誰かが反応に指を突っ込んで、これらは代数的な効果であり、あなたが望むことは何でもできると言います。 上記の例はすべて、本質的にこれらの代数効果とモックの使用です。 私とDIにとって、これらはmokiです。







PS:この投稿は、Reactチームがすべてを壊したという事実についてのReact / RFCのコメントへの応答として書かれており、 そこにあるすべてのポリマーもそうです。

PPS:この投稿は実際には別の非常に無料の翻訳です

PPPS:一般的に、本当の分離のために、 rewiremockを見てください



All Articles