【发布时间】:2012-05-08 12:58:51
【问题描述】:
这必须是微不足道的,但是对于 TDD 来说还是个新手,我想不出正确的方法。
假设我们有一个 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
与this问题相同。
现在,一定有一些琐碎的事情让我无法理解。据我所知,让LoadModules() 返回IEnumerable<IModule> 是一件好事™。将返回类型更改为 IEnumerable<Module> 当然会使代码编译,但它只会将问题转移到单元测试。
我有点困惑,也许我做错了(如果是这种情况,我很抱歉)。
那么,你会怎么做呢?如何使 Module 可模拟?
【问题讨论】:
标签: c# .net-3.5 mocking covariance contravariance