MEF和工厂模式

时间:2011-05-03 09:40:58

标签: c#-4.0 dependency-injection mef factory-pattern testability

我正在尝试重构我的项目以提高可测试性,因此我引入了一个抽象工厂。

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

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

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

下一步是介绍ITwitterClientFactory DefaultTwitterClientFactory创建TweetSharpTwitterClient的{​​{1}}。这应该让我更接近我的目标(可测试性),因为我可以将工厂切换到创建MockTwitterClientFactory的{​​{1}},从而提供一些测试输出。

现在,让我谈谈我的观点。 我正在使用MEF进行依赖注入(但我对它很新)。我正在做的是:

MockTwitterClient

我的public class TwitterCrawler : CrawlerBase, ICrawler { [Import] public ITwitterClientFactory TwitterClientFactory {get; set;} public override Process() { ITwitterClient twitterClient = TwitterClientFactory.MakeSingletonClient(); // do something with twitterClient } } 将自己导出到MEF:

DefaultTwitterClientFactory

现在,虽然这个工作到目前为止,我的问题是,如何切换工厂? 如何创建单元测试并使用[Export(typeof(ITwitterClient))] public class DefaultTwitterClientFactory: ITwitterClientFactory { // implementation of ITwitterClientFactory // provides methods to create instances of ITwitterClient implementations } 而不是MockClientFactory

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

DefaultTwitterClientFactory

甚至

... new TwitterCrawler(mockedTwitterClientFactory)

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

我应该更多地了解MEF的机制(ExportProvider?)

1 个答案:

答案 0 :(得分:3)

shouldn't need to use the composer/container in your unit tests - 只需将SUT直接与Test Doubles相符。

这样的事情:

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

但是,您应该从Property Injection到Constructor Injection重构,因为该属性暗示依赖是可选的。

BTW,您的DefaultTwitterClientFactory不会自行导出,而是导出ITwitterClient。