2012-10-21 29 views
1

可以說我有在C#下面的代碼:注入第三方類,而無需創建工廠

public class AppleTree 
{ 
    public AppleTree() 
    { 
    } 

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

,其中水果是不具備的接口第三方類。

我想創建一個AppleTree類的單元測試,但我不想運行Fruit類。相反,我想注入Fruit類,以便在測試中嘲笑它。

我應該怎麼做呢?我可以創建一個工廠,創建的蘋果,然後在接口添加到該工廠,如:

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

現在我可以注入IFruitFactory到蘋果樹和使用CreateApple,而不是新的果實爲:

public class AppleTree 
{ 
    private readonly IFruitFactory _fruitFactory; 

    public AppleTree(IFruitFactory fruitFactory) 
    { 
     _fruitFactory = fruitFactory 
    } 

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

現在我的問題是:有沒有創建工廠這樣做的好方法?例如,我可以用某種方式使用像Ninject這樣的依賴注入器類的框架嗎?

回答

0

Ninject.Extensions.Factory - 有了它,你有Func<T>構造函數參數和後臺生成抽象工廠(一拉@雷納德的+1回答)

(您也可以定義一個Abstract Factory接口並有Ninject.Extensions.Factory實施它

+0

有趣的解決方案,我會試試 有一個博客文章作者解釋它[這裏](http://www.planetgeek.ch/2011/12/31/ ninject-extensions-factory-introduction /) – Martin

+0

祝你好運(順便說一下,博客文章是我鏈接到的wiki文章的來源材料 - 並記住它的wiki,所以任何讓你困惑的東西或你擁有的任何好點子,都要編輯一些東西!) –

1

你可以模擬出實現的類型。我知道的產品做得非常好,是Typemock。微軟有一個名爲Moles的產品,但我沒有遇到任何實際使用它的人。我沒有太多的投入到它的用處。

您還可以向運行時註冊COM接口以攔截創建對象以注入自己的對象。這就是這些產品的工作原理。這些是代碼更改量最少的地方,以獲得您想要的位置。

長期以來我會傾向於用工廠或類似的東西來提取水果。但是像Typemock或Moles這樣的工具會在短期內讓你更快。如果一切都在一個界面之後,它會減少前進的摩擦。

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是你的單元測試
1

創建也許,最簡單的,實現自己的抽象FruitBase類,虛擬方法/屬性一個模擬IFruit對象。然後讓包裝的實現水果類 - FruitWrapper。相同的邏輯HttpContextBaseHttpContextWrapper的HttpContext的System.Web

然後,您可以輕鬆地嘲笑一切,無需任何供應商特定的黑魔法測試框架。

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")

0

如果你不能編程到IFruit接口,那麼我認爲抽象工廠就是要走的路。對於單元測試,如果您使用的是Visual Studio 2012,則可以嘗試Microsoft Fakes。下面的代碼只是爲了好玩(當然它是有效的)。也許這對你的情況是過度的。

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()); 
      } 
     } 
    } 
}