15

全て、

これについていくつか考えてみたいと思います。最近、私は設計/開発の際に「純粋主義者」の DI/IOC 原則のサブスクライバーになりつつあります。これの一部 (大部分) には、クラス間の結合がほとんどないこと、およびそれらの依存関係がコンストラクターを介して解決されることを確認することが含まれます (これを管理する方法は確かに他にもありますが、アイデアはわかります)。

私の基本的な前提は、拡張メソッドが DI/IOC の原則に違反しているということです。

データベーステーブルに挿入された文字列が適切なサイズに切り捨てられるようにするために使用する次の拡張メソッドを作成しました。

public static class StringExtensions
{
    public static string TruncateToSize(this string input, int maxLength)
    {
        int lengthToUse = maxLength;
        if (input.Length < maxLength)
        {
            lengthToUse = input.Length;
        }

        return input.Substring(0, lengthToUse);
    }
}

次に、次のように別のクラス内から文字列を呼び出すことができます。

string myString = "myValue.TruncateThisPartPlease.";
myString.TruncateToSize(8);

拡張メソッドを使用せずにこれを公正に翻訳すると、次のようになります。

string myString = "myValue.TruncateThisPartPlease.";
StaticStringUtil.TruncateToSize(myString, 8);

上記の例のいずれかを使用するクラスは、TruncateToSize メソッドを含むクラスとは別にテストできませんでした (TypeMock は別として)。拡張メソッドを使用しておらず、静的な依存関係を作成したくない場合は、次のようになります。

string myString = "myValue.TruncateThisPartPlease.";
_stringUtil.TruncateToSize(myString, 8);

最後の例では、_stringUtil の依存関係がコンストラクターによって解決され、実際の TruncateToSize メソッドのクラスに依存せずにクラスをテストできます (簡単にモックできます)。

私の見解では、最初の 2 つの例は静的な依存関係 (1 つは明示的、もう 1 つは非表示) に依存していますが、2 番目の例は依存関係を逆転させ、結合を減らし、テスト容易性を高めています。

では、拡張メソッドの使用は DI/IOC の原則に反しますか? IOC 方法論のサブスクライバーである場合、拡張メソッドの使用を避けますか?

4

4 に答える 4

18

TruncateToSize現実的に交換可能なコンポーネントではないので、問題ないと思います。これは、1 つのことだけを行う必要があるメソッドです。

すべてをモックアウトできる必要はありません。単体テスト (ファイル アクセスなど) を妨害するサービス、または真の依存関係に関してテストしたいサービスだけです。認証などを実行するためにそれを使用していた場合、それは非常に異なる問題になります...しかし、構成可能性や異なる実装オプションなどをまったく持たない単純な文字列操作を行うだけです-それを依存関係と見なす意味はありません通常の意味で。

別の言い方をすればTruncateToSize、 の真のメンバーだった場合String、それを使用することについてよく考えますか? などを導入して、整数演算もモックアウトしようとしていますIInt32Adderか? もちろん違います。これはまったく同じです。たまたま実装を提供しているだけです。単体テストを行ってTruncateToSizeください。心配する必要はありません。

于 2009-08-18T22:45:34.347 に答える
17

どこから来たのかはわかりますが、拡張メソッドの機能をモックアウトしようとしている場合は、それらを間違って使用していると思います. 拡張メソッドは、それらがなければ構文的に不便なタスクを実行するために使用する必要があります。あなたの TruncateToLength は良い例です。

TruncateToLength のテストでは、モックを作成する必要はありません。いくつかの文字列を作成し、メソッドが実際に適切な値を返すことをテストするだけです。

一方、データ ストアにアクセスする拡張メソッドに含まれるコードがデータ層にある場合は、問題があり、テストが問題になります。

私は通常、小規模で単純な操作に構文糖衣を提供するために拡張メソッドのみを使用します。

于 2009-08-18T22:42:57.770 に答える
1

拡張メソッド、部分クラス、および動的オブジェクト。私は彼らが本当に好きですが、慎重に踏まなければなりません。ここにはモンスターがいます。

私は動的言語を見て、それらが日常的にこの種の問題にどのように対処しているかを見て、本当に啓発的でした. 特に、優れた設計と規律を除けば、彼らが愚かなことをするのを止めるものがない場合. すべてが実行時に動的であり、それらを停止する唯一のことは、コンピューターが重大な実行時エラーをスローすることです。「ダックタイピング」は私が今まで見た中で最も狂ったものです。優れたコードは、優れたプログラム設計、チーム内の他の人への敬意、そしてすべてのメンバーの信頼にかかっています。デザインはより良い結果につながります。

モック オブジェクト/ICO/DI を使用したテスト シナリオに関しては、拡張メソッドに負荷の高い作業を入れるのか、それとも関数型の方法で動作する単純な静的なものを入れるのか? 私はあなたが関数型プログラミング スタイルで行うようにそれらを使用する傾向があります。入力が入り、途中で魔法を使わずに結果が出てきます。MS の人たちが設計およびテストしたことを知っているフレームワーク クラスをまっすぐにします。信頼できる :Pの上。

拡張メソッドを使用して重労働を行っている場合は、プログラム設計をもう一度見て、CRC 設計、クラス モデル、ユース ケース、DFD、アクション ダイアグラムなど、使用したいものをすべてチェックし、この設計のどこで使用するかを見つけます。これを適切なクラスではなく拡張メソッドに入れることを計画しました。

結局のところ、システム設計に対してのみテストでき、スコープ外のコードはテストできません。拡張クラスを使用する場合は、代わりにオブジェクト構成モデルを検討し、非常に正当な理由がある場合にのみ継承を使用することをお勧めします。

オブジェクト構成は、堅実なコードを生成するため、常に私に勝っています。それらを差し込んで、取り出して、好きなことをすることができます。これはすべて、設計の一部としてインターフェイスを使用するかどうかによって異なります。また、Composition クラスを使用すると、クラス階層ツリーが個別のクラスにフラット化され、継承されたクラスを通じて拡張メソッドが取得される場所が少なくなります。

拡張メソッドの場合のように、別のクラスに作用するクラスを使用する必要がある場合は、最初に訪問者パターンを調べて、それがより良いルートかどうかを判断してください。

于 2011-08-04T02:31:05.143 に答える
0

彼らは嘲笑するのが難しいので、それは苦痛です。私は通常、これらの戦略のいずれかを使用します

  1. うん、モックアウトするためのPITAである拡張機能を破棄します
  2. 拡張機能を使用して、正しいことをテストするだけです。つまり、切り捨てにデータを渡し、切り捨てられたことを確認します
  3. それが些細なことではなく、それをモックする必要がある場合は、拡張クラスに使用するサービスのセッターを持たせ、それをテスト コードに設定します。

すなわち

static class TruncateExtensions{

    public ITruncateService Service {private get;set;}
    public string TruncateToSize(string s, int size)
    {
         return (Service ?? Service = new MyDefaultTranslationServiceImpl()). TruncateToSize(s, size);
    }
}

誰かがサービスを設定してはいけないときに設定する可能性があるため、これは少し怖いですが、私は時々少し無頓着です。それが本当に重要な場合は、#if TEST フラグまたは回避する ServiceLocator パターンで何か賢いことをすることができます本番環境で使用されているセッター。

于 2009-08-18T22:53:27.610 に答える