2013-07-25 72 views
0

我需要一些如何单元测试这种方法。问题是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); 
     } 
    } 

回答

1

看来你只用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; } 
} 
+0

我使用C#而不是Java。对不起,我没有在帖子中说过。我想这就是我要做的。看起来很奇怪,但有一个接口只用于测试。但是,我正在wh end结束。 – Jordan

+0

@Jordan:那么,在基于反射的嘲笑框架很常见之前,就是这么做的;)我对犀牛(或C#)不熟悉,不知道是否有更好的方法来实现这一点,恐怕... –

0

您应该FsFileGroupFile提取一些接口,并把它传递到构造函数的参数。 然后,你可以轻松地用你喜欢的框架犀牛嘲笑这个接口,在你的情况。

如果不合适,您应该构建您的FsFileGroupFile,并且在将参数传递给它的复杂构造函数时可能会使用mock。

似乎没有其他选择,除了可能你应该在这里审查你的设计。如果班级如此难以测试,它可能是设计不佳的标志。

0

当我不得不在测试中创建复杂的对象时,我使用了Test Data Builder Pattern。作为例子,让我们假设你有五个值传递给构造函数:

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" 
} 

注:犀牛嘲笑或许可以为您的默认值,但我没有用它PERS所以我不确定。

// Override the properties in each test 
fsFileGroupBuilder.ThirdProperty = "Value needed for unit test." 

// create 
var fileItemData = new FileItemData(); 
ReadGeneral(fsFileGroupBuilder.Build(), fileItemData); 

还有其他的开源库,可以产生诸如NBuilder测试数据已经在过去的工作很适合我的帮助。

这里的要点是复杂的构造函数可以用一个构建器抽象出来,它可以让你专注于测试业务逻辑,而不是在每个测试中都满足构造函数。

相关问题