具有构造函数的依赖项的单元测试
本文关键字:单元测试 依赖 构造函数 | 更新日期: 2023-09-27 18:24:54
我需要了解如何对这个方法进行单元测试。问题是FsFileGroupFile不容易被嘲笑,它有复杂的构造函数需求,并且不直接使用接口。_blockReaderFactory
是一个接口,因此很容易模拟。我怎么能嘲笑这么复杂的物体呢。我使用的是Rhino Mocks和Microsoft单元测试框架。有人有什么想法吗?
public void ReadGeneral(FsFileGroupFile a_file, FileItemData a_fileItemData)
{
try
{
var blockReader = _blockReaderFactory.Create(a_file.File.FullName, "CabinetData/StartData");
var version = blockReader.ReadVersion();
var name = blockReader.ReadString();
var type = blockReader.ReadString();
var defaultHeight = blockReader.ReadDouble();
var defaultWidth = blockReader.ReadDouble();
var defaultDepth = blockReader.ReadDouble();
a_fileItemData.Name = name;
a_fileItemData.DefaultWidth = defaultWidth * 100.0;
a_fileItemData.DefaultHeight = defaultHeight * 100.0;
a_fileItemData.DefaultDepth = defaultDepth * 100.0;
}
catch (Exception ex)
{
throw new IOException("General data could not be read from block data.", ex);
}
}
您似乎只是在使用a_file
来获取文件名。那么,为什么不创建一个接口FilenameSupplier
(或类似的接口),并编写一个实现它的包装器呢?
Java代码示例(添加在问题标记为C#之前…):
interface FilenameSupplier {
String getName();
}
public void ReadGeneral(FilenameSupplier a_file, FileItemData a_fileItemData) {
...
a_file.getName();
...
}
class ConcreteSupplier implements FilenameSupplier {
private final FsFileGroupFile file;
public ConcreteSupplier(FsFileGroupFile file) { this.file = file; }
String getName() { return a_file.File.FullName; }
}
您应该从FsFileGroupFile
中提取一些接口,并将其传递到构造函数参数中。然后,您可以使用您喜欢的框架Rhino Mocks轻松地模拟这个接口。
如果不合适,您应该构建FsFileGroupFile
,并且在其复杂构造函数中传递参数时可能会使用mock。
似乎没有其他选择,除了可能你应该在这里审查你的设计。如果类很难测试,这可能是设计糟糕的标志。
当我不得不在测试中创建复杂的对象时,我使用了测试数据生成器模式。举个例子,假设您有五个值要传递给构造函数:
public FsFileGroupFile(string firstProperty, string secondProperty,
string thirdProperty, string fourthProperty, string fifthProperty)
{
// constructor logic goes here
}
然后,它将在单元测试项目中用一个测试构建器类包装:
public class FsFileGroupFileBuilder
{
public string FirstProperty { get; set; }
public string SecondProperty { get; set; }
public string ThirdProperty { get; set; }
public string FourthProperty { get; set; }
public string FifthProperty { get; set; }
public FsFileGroupFile Build()
{
return new FsFileGroupFile(FirstProperty, SecondProperty, ThirdProperty,
FourthProperty, FifthProperty);
}
}
现在,您可以只为您关心的属性分配值,并以这种方式构建对象:
// in your test setup use this to initial to a default/valid state
var fsFileGroupBuilder = new fsFileGroupBuilder
{
FirstProperty = "Default",
SecondProperty = "Default",
ThirdProperty = "Default",
FourthProperty = "Default",
FifthProperty = "Default"
}
注意:Rhino Mocks可能会为您设置这些默认值,但我个人没有使用过,所以我不确定。
// Override the properties in each test
fsFileGroupBuilder.ThirdProperty = "Value needed for unit test."
// create
var fileItemData = new FileItemData();
ReadGeneral(fsFileGroupBuilder.Build(), fileItemData);
还有其他的开源库可以帮助生成测试数据,比如NBuilder,它在过去对我来说很好。
这里的要点是,复杂的构造函数可以用构造函数抽象出来,这将使您能够集中精力测试业务逻辑,而不是在每次测试中都满足构造函数的要求。