3

私は古い 3 層設計のプロジェクトに取り組んでいます。追加された新しい機能は、単体テスト可能である必要があります。

問題は、以下のサンプルのように、ビジネス層/データ層が密結合していることです。BL はデータ層オブジェクトをニュースアップするだけなので、この方法でモックアップすることはほとんど不可能です。依存性注入は実装されていないため、コンストラクター注入は不可能です。では、DI を使用せずにデータ層をモックアップできるように構造を変更する最善の方法は何でしょうか?

public class BLLayer()
{

   public GetBLObject(string params)
   {
     using(DLayer dl = new DLayer())
     {  
        DataSet ds = dl.GetData(params);

        BL logic here....

     }
   }
}
4

3 に答える 3

5

コンストラクターインジェクション自体を除外しているわけではありません。IOCコンテナーが設定されていないだけです。それは結構です、あなたはそれを必要としません。Poor Manの依存性注入を実行しても、コンストラクター注入を維持できます。

DataLayerをインターフェイスでラップしてから、IDataLayerコマンドでオブジェクトを作成するファクトリを作成します。これを注入しようとしているオブジェクトのフィールドとして追加し、すべてnewをファクトリへの呼び出しに置き換えます。これで、次のように、テスト用に偽物を挿入できます。

interface IDataLayer { ... }
interface IDataLayerFactory 
{
   IDataLayer Create();
}    

public class BLLayer()
{
  private IDataLayerFactory _factory;

   // present a default constructor for your average consumer
  ctor() : this(new RealFactoryImpl()) {} 

  // but also expose an injectable constructor for tests
  ctor(IDataLayerFactory factory)
  { 
    _factory = factory;
  }  

  public GetBLObject(string params)
  {
    using(DLayer dl = _factory.Create())  // replace the "new"
    {  
      //BL logic here....    
    }
  }
}

実際のコードで使用する実際のファクトリのデフォルト値を設定することを忘れないでください。

于 2012-06-01T22:12:05.030 に答える
3

依存性注入は、「制御の反転」として知られる包括的な概念に該当する多くのパターンの1つにすぎません。主な基準は、コンポーネント間に「継ぎ目」を設けて、分離できるようにすることです。要するに、猫の皮を剥ぐ方法は複数あります。

依存性注入自体には、コンストラクター注入(コンストラクターを介して渡される依存性)、プロパティ注入(読み取り/書き込みプロパティとして表される依存性)、およびメソッド注入(依存性がメソッドに渡される)といういくつかの派生物があります。これらのパターンは、クラスが「変更のために閉じられている」ことを前提としており、コンシューマーが変更できるように依存関係を公開しています。レガシーコードがこのように設計されることはめったになく、システム全体のアーキテクチャの変更(コンストラクタインジェクションやIoCコンテナへの移行など)は必ずしも簡単ではありません。

他のパターンは、テスト中の対象から離れたオブジェクトの解像度および/または構造を分離することを含みます。工場のような4つのパターンの単純なギャングは驚異を行うことができます。Service Locatorはグローバルオブジェクトファクトリのようなものであり、私はこのパターンの大ファンではありませんが、依存関係を切り離すために使用できます。

上で概説した例では、テストパターン「Subclassto Test」を使用すると、システム全体を再構築せずにシームを導入できます。このパターンでは、「new DLayer()」などのオブジェクト作成呼び出しを仮想メソッドに移動してから、サブジェクトのサブクラスを作成します。

MichealFeatherの「WorkingwithLegacyCode」には、レガシーコードをDIに移行できる状態にするために使用できるパターンと手法のカタログがあります。

于 2012-06-02T14:02:40.717 に答える
2

DLayerメソッドでのみ使用される場合はGetBLObject、メソッド呼び出しにファクトリを挿入します。次のようなもの:(@PaulPhillipsの例に基づいて構築)

public GetBLObject(string params, IDataLayerFactory dataLayerFactory)
   {
       using(DLayer dl = dataLayerFactory.Create())  // replace the "new"
       {  
            //BL logic here....    
       }
   }

ただし、ビジネスレイヤーで本当に操作したいのはDataSet. 別の方法は、メソッド呼び出しで の代わりに を使用することGetBLObjectです。その作業を行うために、から を取得するだけを処理するクラスを作成できます。例えば:DataSetstring paramDataSetDLayer

public class CallingBusinesslayerCode
{
    public void CallingBusinessLayer()
    {
        // It doesn't show from your code what is returned
        // so here I assume that it is void. 
        new BLLayer().GetBLObject(new BreakingDLayerDependency().GetData("param"));
    }
}

public class BreakingDLayerDependency
{
    public DataSet GetData(string param)
    {
        using (DLayer dl = new DLayer()) //you can of course still do ctor injection here in stead of the new DLayer() 
        {
            return dl.GetData(param);
        }
    }
}

public class BLLayer
{
    public void GetBLObject(DataSet ds)
    {
        // Business Logic using ds here.
    }
}

1 つの警告: モックアウトDataSet(これと Paul Phillips のソリューションの両方で行う必要があります) は非常に面倒な場合があるため、これをテストすることは可能ですが、必ずしも楽しいとは限りません。

于 2012-06-02T08:38:01.390 に答える