我想创建可模拟对 .Net System.IO 类的调用的单元测试代码,这样我就可以真正进行单元测试,而不是依赖于文件系统。 我正在使用 SystemWrapper 类来包装 BCL 类。
我正在尝试获取一个简单的示例来查看文件是否存在。
我遇到的问题是,在类中注入依赖项不起作用,因为实例化依赖项(通过StructureMap)需要知道要传递什么构造函数参数,这在当时不可用,也没有默认构造函数。
示例代码:
// don't want to create dependency here like so
//IFileInfoWrap fileInfoWrap = new FileInfoWrap(filename);
// using service locator (anti-pattern?!) since it can't be
// injected in this class
var fileInfoWrap = ObjectFactory.GetInstance<IFileInfoWrap>(
new ExplicitArguments(new Dictionary<string, object>
{
{"fileName", filename}
}));
Console.WriteLine("File exists? {0}", fileInfoWrap.Exists);
我不喜欢的是依赖项没有注入,ObjectFactory 不应该在这里(但我看不到其他创建它的方法)。 ExplicitArguments 让它变得混乱,并且参数名称是一个神奇的字符串。
对于我来说,要使其正常工作,StructureMap 配置类需要明确知道我想要使用哪个构造函数(我刚刚开始使用 StructureMap,所以这可能不是设置它的正确方法):
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.AssembliesFromPath(".");
scan.RegisterConcreteTypesAgainstTheFirstInterface();
scan.WithDefaultConventions();
});
// use the correct constructor (string instead of FileInfo)
x.SelectConstructor(() => new FileInfoWrap(null as string));
// setting the value of the constructor
x.For<IFileInfoWrap>()
.Use<FileInfoWrap>()
.Ctor<string>("fileName")
.Is(@".");
});
有人找到了更好的解决方案来针对 System.IO 类创建可测试的代码吗? 我知道部分问题在于 System.IO 类的设计。
我非常成功地使用的一种方法是为
System.IO
和 FCL 的其他部分中找到的类型推出我自己的代理类型。例如。我想依赖System.IO.File
。我创建了一个名为 System.IO.Proxies
的库,并添加了一个具体类型 File
和一个接口 IFile
。接口 IFile
公开了与我从 System.IO.File
需要的所有成员等效的成员,并且具体类型除了将方法调用转发到 System.IO.File
之外什么也不做,来实现这些成员。 System.IO.Proxies
被排除在单元测试和代码覆盖率之外。在我的消费程序集中,我仅依赖于 System.IO.Proxies
,具体来说,我仅依赖于 IFile
。这样我就可以轻松模拟这种依赖关系,并为我的消费程序集实现 100% 的代码覆盖率。
(请注意,这是我对上一个问题的更一般的答案的定制版本。)
您还可以尝试使用库https://github.com/Tum4ik/stinim-gen。 它为指定类的静态成员生成一个接口和一个实现包装器。