1

C#に次のコードがあるとしましょう。

public class AppleTree
{
   public AppleTree()
   {
   }

   public string GetApple
   {
      return new Fruit("Apple").ToString();
   }
}

ここで、Fruitは、インターフェースを持たないサードパーティのクラスです。

AppleTreeクラスの単体テストを作成したいのですが、Fruitクラスを実行したくありません。代わりに、Fruitクラスを注入して、テストでモックできるようにします。

どうすればこれを行うことができますか?リンゴを作成するファクトリを作成してから、次のようにこのファクトリにインターフェイスを追加できます。

public class FruitFactory : IFruitFactory
{
   Fruit CreateApple()
   {
      return new Fruit("Apple");
   }
}

これで、IFruitFactoryをAppleTreeに挿入し、新しいFruitの代わりにCreateAppleを次のように使用できます。

public class AppleTree
{
   private readonly IFruitFactory _fruitFactory;

   public AppleTree(IFruitFactory fruitFactory)
   {
      _fruitFactory = fruitFactory
   }

   public string GetApple
   {
      return  _fruitFactory.CreateApple().ToString();
   }
}

さて、私の質問です。工場を作成せずにこれを行う良い方法はありますか?たとえば、Ninjectのような依存性注入の名声を何らかの方法で使用できますか?

4

5 に答える 5

1

実装された型をモックアウトできます。私が知っている製品は、これをかなりうまく行っています。Typemockです。MicrosoftにはMolesという製品がありますが、実際に使用している人には会ったことがありません。私はそれの有用性について多くのインプットを持っていません。

COMインターフェイスをランタイムに登録して、オブジェクトの作成をインターセプトして独自のオブジェクトを挿入することもできます。それがこれらの製品の仕組みです。これらは、必要な場所に到達するためのコード変更の最小量です。

長期的には、工場などでフルーツを抽象化することに傾倒します。しかし、TypemockやMolesのようなツールを使用すると、短期的にはより早くそこにたどり着くことができます。すべてがインターフェースの背後にある場合は、前進する際の摩擦が少なくなります。

于 2012-10-21T12:47:47.997 に答える
1

おそらく、最も単純なのは、仮想メソッド/プロパティを使用して、独自の抽象FruitBaseクラスを実装することです。次に、実際のFruitクラスをラップする実装を作成します-FruitWrapperSystem.WebのHttpContextBaseHttpContextWrapper、およびHttpContextと同じロジック。

そうすれば、ベンダー固有のダークマジックテストフレームワークがなくても、すべてを簡単にモックできます。

public class AppleTree
{
    private readonly Func<FruitBase> _constructor;
    public AppleTree(Func<FruitBase> constructor)
    {
        _constructor = constructor;
    }

    public string GetApple()
    {
        return new _constructor().ToString();
    }
}

また、コンストラクターで関数を交換できます:() => new FruitMock()() => new Fruit("Apple")

于 2012-10-21T13:51:57.943 に答える
0

IFruitインターフェースにプログラムできなかった場合は、AbstractFactoryが最適だと思います。

単体テストに関しては、Visual Studio 2012を使用している場合は、MicrosoftFakesを試すことができます。次のコードは楽しみのためだけのものです(もちろん機能します)。多分それはあなたの場合にはやり過ぎです。

using Microsoft.QualityTools.Testing.Fakes;
using MyLib;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            using (ShimsContext.Create())
            {
                MyLib.Fakes.ShimFruit.ConstructorString = delegate(Fruit f, string s)
                {
                    var shimFruit = new MyLib.Fakes.ShimFruit(f);
                    shimFruit.ToString = () =>
                    {
                        return "Orange";
                    };
                };
                AppleTree tree = new AppleTree();
                string expected = "Orange";
                Assert.AreEqual(expected, tree.GetApple());
            }
        }
    }
}
于 2012-10-21T17:28:52.343 に答える
0

通常、ファクトリではなくFruit、インターフェイスを実装しIFruitて、代わりにそれを注入します。

public class AppleTree
{
    private readonly IFruit _apple;

    public AppleTree(IFruit apple)
    {
        _apple = apple;
    }

    public string GetApple()
    {
        return _apple.ToString();
    }
}

この種の実装では、次のいずれかをインスタンス化できます。

  1. new AppleTree(new Fruit("Apple"))または、NInjectやStructureMapなどのIoCコンテナに代わって実行させることもできます
  2. new AppleTree(mockApple)mockAppleユニットテスト用に作成したモックIFruitオブジェクトはどこにありますか
于 2012-10-21T12:57:59.977 に答える
0

参照Ninject.Extensions.Factoryしてください-それを使用すると、Func<T>ctor引数があり、Abstract Factoryが舞台裏で生成されます(@Nenadの+1の回答)

抽象ファクトリインターフェイスを定義して、 Ninject.Extensions.Factoryに実装させることもできます。

于 2012-10-21T20:28:47.057 に答える