JavaScriptでプライベートをモックする

問題



非表示関数の使用を分離することにより、クロージャー関数またはインターフェイスをテストする必要がある場合があります。 また、テスト後の状態を考慮するために、隠し変数の初期状態を設定する必要がある場合があります。 この場合、オブジェクトの内部へのアクセスを提供する追加の関数セットを構築しています。 多くの場合、このセットは非常に面倒で、モジュールのテスト容易性を確保することのみを目的としています。



しかし、このコードを書くことを避ける簡単な方法があります。



叙情的な余談


JavaScriptと単体テストは初めてです。 たぶん、このソリューションはすでにmightとmainで使用されていますが、私はそれを自分で見つけ、他の人と共有するのを急いでいます。



解決策



広く知られている(そして多くの人に嫌われている)関数eval()



は、その呼び出しの字句コンテキストで指定されたコードを実行することがわかりました。

これにより何が得られますか?

複雑なAPIの代わりに、すべての作業を行う関数を1つだけ追加できます。

  this.evalInContext = function(cmd){eval(cmd);} 




オブジェクトは次のようになります。

 function factory(params){ var outerVar; function outerFunc(){} function MyClass(params2){ var innerVar; function innerFunc(){} this.instanceVar = 0; this.instanceFunc(){} this.evalInContext = function(cmd){eval(cmd);} } return new Myclass(params); }
      
      





この使用により、すべての引数、および外部、内部、およびオブジェクトの関数と変数が、 eval ()



渡されるコードで使用可能になります。



使用する


 var myObj = factory(); // create an object myObj.evalInContext("outerVar=10;innerVar='zzz';this.instanceVar=new Date();"); //set private and instance variables myObj.evalInContext("innerFunc();outerFunc(111);"); // call functions
      
      





拡張機能



変数に単純な値を設定するか、単純なパラメーターで関数を呼び出すには、 evalInContext()



直接呼び出しを使用できます。 しかし、より複雑なオブジェクトを扱う必要がある場合はどうでしょう。

evalInContext()



コア機能を拡張するいくつかの簡単な関数を作成しました。



複雑な変数の設定と取得


セッターは次のようになります。

 function setVar(obj, name, value){ obj.evalInContext("name + " = arguments[1]", value); }
      
      





値をパラメーターとしてevalInContext()



関数に渡し、 arguments



を使用してデータを割り当てます。 これにより、あらゆるタイプのデータを転送できます。

ゲッターも同様に機能しますが、別の簡単なトリックを使用します。

 function getVar(obj, name){ var res = {}; obj.evalInContext("arguments[1]['" + name + "'] = " + name + ";", res); return res[name]; }
      
      





return



eval()



関数では使用できないため、空のオブジェクトを戻り値のコンテナとして渡します。



UPD :コメントでは、より興味深いオプションが提案されました。 そして、私にとってはより正確です。



関数置換(モッキング)


関数名は変数なので、既存の機能を使用できます。

 function replaceFunction(obj, name, replacement) { var orig = getVar(obj, name); setVar(obj, name, replacement); return orig; }
      
      





複雑なパラメーターを使用した関数呼び出し


関数を呼び出すラッパーを作成することもできますが、関数自体を取得して通常の方法で呼び出す方が簡単です。 また、一度受信すると、好きなだけ電話をかけることができます。

関数を取得するには、すでに利用可能なゲッターを使用できます。



落とし穴



もちろん、このソリューションは完璧ではありません。 たとえば、リファクタリングは、文字列内やモジュールの外部でさえ、内部変数と関数の名前の使用を簡単に見つけることができます。 これにより、テストサポートが大幅に複雑になる可能性があります。



さらに、この関数はすべてのコードセキュリティ概念を完全に破壊するため、最終的なコードから削除する必要があります。



All Articles