2011-05-03 119 views
2

我正在尝试重构我的项目以提高可测试性,因此我介绍了一个抽象工厂。MEF和工厂模式

我的应用程序使用ICrawlers收集不同来源的数据。 这些ICrawler使用第三方库来访问不同的来源,例如,推特。

示例:我的TwitterCrawler使用TweetSharp访问Twitter数据。

我的第一个版本强烈地将TweetSharp客户端与Crawler结合在一起。现在我将TweetSharp抽象为ITwitterClientTweetSharpTwitterClient实现。

下一步是引入ITwitterClientFactoryDefaultTwitterClientFactory创建TweetSharpTwitterClient s。这应该使我更接近我的目标(可测试性),因为我可以将工厂切换到MockTwitterClientFactory,创建MockTwitterClient,它提供了一些测试输出。

现在,让我来谈谈我的观点。 我正在使用MEF进行依赖注入(但我对它很陌生)。我在做什么是这样的:

public class TwitterCrawler : CrawlerBase, ICrawler 
{ 
    [Import] 
    public ITwitterClientFactory TwitterClientFactory {get; set;} 

    public override Process() 
    { 
     ITwitterClient twitterClient = TwitterClientFactory.MakeSingletonClient(); 
     // do something with twitterClient 
    } 
} 

而我DefaultTwitterClientFactory出口本身MEF:

[Export(typeof(ITwitterClient))] 
public class DefaultTwitterClientFactory: ITwitterClientFactory 
{ 
    // implementation of ITwitterClientFactory 
    // provides methods to create instances of ITwitterClient implementations 
} 

现在,虽然到目前为止是这种情况,我的问题是,如何切换工厂? 如何创建单元测试并使用MockClientFactory而不是DefaultTwitterClientFactory

我的方法很好吗?手动设置要使用的工厂是否更好? 某处像

... new TwitterCrawler(mockedTwitterClientFactory)

甚至

.... new TwitterCrawler(mockedTwitterClient)

这实际上只是将问题移出TwitterClient之外,但仍然需要决定如何构建ITwitterClient以及用于该目的的工厂。

我应该更深入进入MEF的机制(ExportProvider?)

回答

3

shouldn't need to use the composer/container in your unit tests - 刚刚与Test Doubles接线SUT直接。

事情是这样的:

var sut = new TwitterCrawler(); 
sut.TwitterClientFactory = new FakeTwitterClientFactory(); 

但是,你真的应该从物业注射重构为构造函数注入,与物业暗示的依赖是可选的。

顺便说一句,您的DefaultTwitterClientFactory不会自行导出,它会导出ITwitterClient。

+0

感谢马克。这对我来说真的很有意义。无论使用什么DI,测试都应运行,因此将其从SUT中移除将重点放在要测试的设备上。我知道了! – Stefan 2011-05-03 13:10:55