这必须是微不足道的,但对TDD来说是相当新的,我找不到正确的方法来做到这一点。如何正确地模拟.NET 3.5
比方说,我们有一个WinForms应用程序,作为其启动过程的一部分,在给定文件夹中查找DLL以动态填充其主菜单栏。
这些DLL仅仅是插件:它们都实现了一个接口,并且它们都将显示为菜单条目。这真的很简单。
让我们调用每个DLL一个Module
。现在
,我想:“嘿,史蒂夫,你得嘲笑这个Module
对象。让我们来定义一个名为IModule
一个接口,使Module
类实现它。这样,你可以嘲笑他们为你请”。
所以,让我写了几行代码,具体IModule
和Module
(我在写这个直不支持编译器,所以它可能无法编译):
<!-- language: c# -->
public interface IModule {
string Id { get; }
string DisplayName { get; }
}
public class Module : IModule {
public string Id { get; }
public string DisplayName { get; }
public string Path { get; private set; }
public Module(FileInfo path) {
Path = path.FullName;
}
}
而且,虽然我们在这,让我们实现了类,将执行实际负载:
public class ModuleLoader {
IEnumerable<DirectoryInfo> SearchPaths;
public ModuleLoader(IEnumerable<DirectoryInfo> searchPaths) {
SearchPaths = searchPaths;
}
public IEnumerable<IModule> LoadModules() {
var modules = SearchPaths
.Where(dir => dir.Exists)
.SelectMany(dir => dir.GetFiles("*.dll").Select(dll => new Module(dll)));
return modules;
}
}
这里谈到的问题:LoadModules()
不会从-我可以收集方差问题,编译,因为。
错误消息如下:
不能键入System.Collections.Generic.IEnumerable <模块>隐式转换为System.Collections.Generic.IEnumerable <的IModule >
哪个与this相同。
现在,一定有一些微不足道的东西可以逃脱我。据我所知,使LoadModules()
返回IEnumerable<IModule>
合格作为一件好事™。将返回类型更改为IEnumerable<Module>
当然会使代码编译,但它只会将问题转移到单元测试。
我有点困惑,也许我做的都是错的(我很抱歉,如果是这样的话)。
那么,你会怎么做呢?我如何使Module
可嘲弄?
更换
new Module(dll)
所以......就是这样,是吧?简单的演员。我真的需要一个假期。谢谢你,@DevinB。为什么我必须将一个实现了某个接口的类的实例投射到同一个接口上的确切原因仍然不太清楚,我想我必须真正阅读Eric Lippert关于差异的文章。顺便说一下,替换'var'并不是真的需要,如果真的需要,我会非常惊讶。再次感谢。 – 2012-04-27 19:27:55我知道替换var并不是真的需要,但最好清楚一点,特别是在像这样的情况下,整个问题是LINQ查询返回一个意外的类型。在这种情况下,清晰度是发现和消除漏洞的最重要因素。 – DevinB 2012-04-27 19:34:34
公平点,DevinB。非常感谢你。现在我可以嘲笑:) – 2012-04-27 19:41:57