我正在尝试重构我的项目以提高可测试性,因此我引入了一个抽象工厂。
我的应用程序使用ICrawlers
从不同来源收集数据。
这些ICrawler
使用第三方库来访问不同的来源,例如推特。
示例:我的TwitterCrawler使用TweetSharp来访问Twitter数据。
我的第一个版本将TweetSharp客户端强烈耦合到Crawler。现在我将TweetSharp抽象为ITwitterClient
和TweetSharpTwitterClient
实现。
下一步是介绍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?)
答案 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。