緩いテストでの厳密な型付け

10年以上、私の仕事の_big__は純粋なJavaScriptです。 しかし、場合によっては、もう少し型付けされた言語を扱う必要があります。 そして、そのような接触の後、毎回「理解不能」という奇妙な感覚が残っています。なぜjsでは同じことができないのですか。



特にできるから。 そして今日は、JavaScriptの最も混oticとした領域、つまり単体テストのモックに少しタイピングを追加しようとします。



そして、ここの誰もが、 モッキングはコーディングの匂いだと言います。







「ない」正しいモカ



mokに対する主な議論は何ですか? 要するに:

分解戦略が失敗した場合、モッキングが必要です。

-エリックエリオットが上記のリンクで述べたように。



ロシア語の場合-



  1. あなたの手は曲がっています
  2. DIを使用してください!
  3. モキ-正直じゃない


1つだけ問題があります-nodejs IoCフレームワークであり、現在実行されているモジュラーシステムはDIです。 原則的に、これがmokas(proxyquire、mockeryなど)の一般的なライブラリが原則として機能する理由です。



つまり、純粋に技術的に-モックはコーディングの匂いではありません。



しかし、問題には別の側面があります-ライブラリ自体が非常に「臭い」がするので、残りのコードに少し感染します。 Proxyquireは曲がっただけで、,笑は遅すぎます。冗談で言えばmokaは特に美しいです。 rewiremockに関する 5月の記事で、この概要を説明しました



「正しいモキー」



mokaとは何か、テストとは何かの「正しさ」は非常に簡単に判断できます。それは正確に落ち、適切な場所に落ちなければなりません。 モックが曲がっている場合、(someFunction).to.be.called()を期待するのではなく、モックが落ちるはずです。 結局のところ、すべてがうまくいくはずなのに、なぜメソッドが呼び出されないのかと長い間不思議に思うかもしれません。



proxyquireには良いコマンドがありました-callThroughを使用すると、「実際の」ファイルを基礎として使用できます。 しかし、どのエクスポートがロックされ、どのエクスポートがロックされていないかを制御するのは難しいため、使用を推奨しませんでした。 ファイルプロセス全体を制御することは困難であるという事実にも注意を払っていません。



Jestには非常に便利な__mock__自動mokシステムがあり、実際のファイルにmokを透過的に提供できます...少し複雑な方法で。 またはすべてまたは何も。 まあ、誰もこれらのモカを制御しません。



mokの主な問題は、tslintの最もワイルドな例であるno-export-by-defaultルールで説明するのは非常に簡単です。



// app.ts import ActionPopover from "./action"; // action.ts export default class ActionMenu { ... } // oops, we just renamed this from popover -> menu but our consumer had no idea!
      
      





mokの場合、さらに楽しくなります。テストは動作し、動作するmokで動作するため、テストは緑色のままですが、実際のファイル(実際のファイルは何でもできます) は存在しません







これが主な問題であり、モックからの主なコーディング臭です。 まあ、彼らは明日への自信を追加しません。



型の安全性



私自身もこの状況に何度か直面し、3度目には技術的に閉鎖することにしました。 より具体的には、 rewiremock v3は、Flow / JSのモックの静的な型指定と、通常のJSの浅いエクスポートチェックをサポートします。



TypeScript vs Flow?
すべての作業を行う10行のTS / Flowを書くのに約1週間かかりましたが、フローに費やした時間の90%で、さらに10行を書き、TSに費やした時間の90%でさらに1週間かかりました。 友情が勝った。



だから-例から始めましょう。



 var foo = proxyquire('./foo', { 'fs': { fileWroteSync } });
      
      





Proxyquireは、それが言うことを正確に行います-依存関係をオーバーロードします。 しかし、彼はそこで実際に何をするかをチェックしません-fsが要求されること、関数がインターセプトされること、操作が有効であること。



モックとその使用の発表は空間的に少し間隔があるため、モックリーはさらに悪化します。



 mockery.registerMock('fs', fsMock); mockery.enable(); const mocked = require(...)
      
      





rewiremockでは、まったく良くありません。 コアAPIがおおざっぱなインターフェースにほぼ従うことを考えると。



 //  API -    . /   rewiremock('./b.js').withDefault(overrideDefault).with({ helper:2});
      
      





これは、mokを作成する一般的な方法です。 彼にとっては、ファイルにデフォルトのエクスポートがあるかどうかと、ヘルパーという名前のエクスポートがあるかどうかです。 上で説明したように、mokと実際のファイルとの不一致は問題であり、「臭い」の主な原因があります。



この状況には2つの解決策があります。



1つ目は、動的インポートを使用します。これは、TS /フローがプロモートされた結果を返すためのものであり、将来の情報は静的型付けによってのみ使用できます。 基礎となるコードは、インポート関数の名前を設定する機能のみをサポートする必要があります。 こんにちは非同期:(



 //  API -  import,      name-resolution rewiremock(() => import('./b.js')) .withDefault(overrideDefault) //  default     .with({ helper: 42 }) // c     
      
      





さらに、必要な情報はすべて、IntelliSenceまたは他のカーコンパイラで利用できます。 動作中の純粋なTypeScript(ウェル、またはフロー)。 これにより、mokiが「より良く」なるだけでなく、mokiを作成する際の「ユーザーエクスペリエンス」も向上します。 IDEがヘルプとプロンプトを表示します。



2番目のオプションはより簡単ですが、文字通り3行のコードがあるため、他のほとんどのライブラリに簡単に移植できるなど、ランタイムでのみ機能します。



 rewiremock('./b.js') .with({ helper: 42 }) .toMatchOrigin(); //  
      
      





この場合、実際のファイルをモック(requireの深さ)に置き換える操作の前に、実際のファイルが実際にロードされ、そのエクスポートが型名の一致についてこのモックと比較されます。



このオプションの主な利点は、同期的に機能することです-結局、これを使用すると便利ですが、動的インポートを使用するには非同期APIを使用する必要がありますが、あまり便利ではありません:(



PS:古き良き同期要求の「タイピング」に問題があるので、試してはいけません。



正直に言うと、mokのタイピングを改善する唯一のことは、mokを書くのにかかる時間(typがある場合)とバグを見つける(両方の場合)です。 理論的には、これが原理的にできるかどうか疑問に思っていたので、基本的にやった。



ジェスト?



Jestは非常に優れているため、ファイル実行のサンドボックス(主要な機能の1つ)に封印された独自のmoxシステムさえ持っています。



このシステムは両面で、__ mocks__ automocksと手動mocksで構成されています。 前者は美しく、後者はひどいです。 Jestの根性では、すべてが悪く、完全に論理的ではありません。node.jsモジュラーシステムをそれ自体とbabelおよびその他すべてに置き換え、すべてのスペースを埋め、「標準」インフラストラクチャ全体を破壊します。 多くの人にとって、これは事実です-proxyquireはJestでは機能しません。 Jestでは何も機能しません。



しかし、私はmokiを入力したいと思います、そして解決策があります。



これは小さなcliユーティリティjest-typed-mockで 、mokを検索してディレクトリをスキャンし、実際のファイルへの準拠をチェックします。



動作モード4:





いくつかの例から始めましたが、「テストは緑色ですが、食べ物はありません」に向かう途中のモックや宗教のさまざまな「蓄積された」矛盾を見つけることができましたが、(神に感謝)まだ到達していません。 正直に言って、このようなシステムがデフォルトでJestに組み込まれているのを見たいです。



参考までに、rewiremockはJestをプッシュして自分自身を軽くたたくのに十分なほど勇敢です。 これを行うには、2つのアクションのみを実行する必要があります-



 // 1.    . //  "" rewiremock  jest-runtime rewiremock.overrideEntryPoint(module); // 2.  require  "" require = rewiremock.requireActual;
      
      





これにより、要求されるファイルのjestが完全に削除されます。サンドボックス化、ローカル変数としてのjest、もちろんjestモック、特に__mocks__はありません...しかし、この注文は受け付けられました。



おわりに



ほぼ1年間、私はrewiremockを見ようとしてきました。 それはproxyquireの代替品として始まり、m笑の代替品として継続し、さらにどこかに沈んだ。



ユーカリの陰でコーヒーを飲むたびに、追加する新機能とその理由を考えます。 それから、これは不可能だと理解します...そして、私は数ヶ月で道を譲ります。

そのため、分離モード、webpack、jestの下での作業、そして今ではタイピングが必要でした。 まあ、もしあなたがmokasの小さなライブラリから%username%から何かを欲しければ-誰に連絡できるか知っているだけです。



リンクの詳細



All Articles