2012-01-05 68 views
0

我有一个应用程序需要文件字典(文件类型和文件名列表),并将文件从原始目录复制到另一个位置。 我已经得到了复制过程的基本代码,但我需要做一些单元测试,以便尽可能健壮。Rhino Mocks测试文件系统io

我有我使用的包装类,所以我可以测试System.IO方法被调用,因为我期望,但我有一些困难,搞清楚如何形成测试,因为有foreach和switch语句在码。下面 示例代码:

private IFileSystemIO _f; 


public CopyFilesToDestination(IFileSystemIO f){ 
    _f = f; 
} 


public void Cpy_Files(Dictionary<string, List<string>> files) 
{ 
// get a list of the file types in the directory 
var listOfFileTypes = new List<string>(files.Keys); 

foreach (var fileType in listOfFileTypes){ 
    var fileList = files[fileType].ToList(); 

    foreach (var file in fileList){ 
     switch(fileType){ 
      case ".txt": 
       _f.Copy(file, @"c:\destination\text"); 
       break; 
      case ".dat": 
       _.Copy(file, @"c:\destination\data"); 
       break; 
     } 
    } 
} 
} 

为了测试我原以为我会用一个模拟字典对象,建立与文件类型和路径的列表,上面:

public virtual Dictionary<string, List<string>> FakeFiles(){ 
    return fakeDictionary = new Dictionary<string, List<string>>(){ 
     {".txt", new List<string>(){ 
      "c:\test\file1.txt", 
       "c:\test\file2.txt" 
      } 
     }, 
     {".dat", new List<string>(){ 
       "c:\test\file1.dat", 
       "c:\test\file2.dat" 
      } 
     }; 
    } 
} 

的第一个测试我来了看起来像这样:

[Test] 
public void Should_Copy_Text_Files(){ 
    var dictionary = new FakeDictionary().FakeFiles(); 

    var mockObject = MockRepository.GenerateMock<IFileSystemIO>(); 
    var systemUnderTest = new CopyFileToDestination(mockObject); 

    systemUnderTest.Cpy_Files(dictionary); 

    // I think this means "test the operation, don't check the values in the arguments"  but I also think I'm wrong 
    mockObject.AssertWasCalled(f => f.Copy("something", "something"), o =>  o.IgnoreArguments()); 

} 

我的第一个问题是:我如何测试一个特定的文件类型,如“.txt”? 那么我该如何测试循环?我用嘲讽的字典知道,我只有两个项目,我是否利用这个来形成测试?怎么样?

我觉得我可能接近一个解决方案,但我没时间/耐心地把它找下来。任何帮助是极大的赞赏。 感谢 吉姆

+0

你如何确定在你的Switch语句中的文件类型是什么..你正在编写的包装代码看起来有点臃肿..如果你想测试一个文件是否有特定的扩展或不是为什么不做这个部分通过使用Path.GetExtension(字符串路径)传入的文件名上的switch语句采用名称为 – MethodMan 2012-01-05 13:55:11

+0

的文件路径文件类型是专有的,实际上是文件名的一部分,实际上不是扩展名。我只是以扩展为例。但要回答您的问题,文件类型将从包含交换机的foreach中的文件类型列表中提取。 – crunchy 2012-01-06 13:30:21

+0

好吧..这更有意义.. – MethodMan 2012-01-06 15:13:27

回答

1

我试过使用Roberts解决方案,但正如我所说的,我有太多不同的文件类型来单独设置每个测试用例。我想接下来的事情是建立一个TestCaseSource,但每次我跑的测试,它标志着试验,忽略:

[Test, TestCaseSource(typeof(FakeDictionary), "TestFiles")] 
public void Cpy_Files_ShouldCopyAllFilesInDictionary(string extension, string fielName) { 
    // Arrange 
    var mockObject = MockRepository.GenerateMock<IFileSystemIO>(); 
    var systemUnderTest = new CopyFileToDestination(mockObject); 

    // Act 
    systemUnderTest.Cpy_Files(dictionary); 

    // Assert 
    mockObject.AssertWasCalled(f => f.Copy(extension, fileName)); 
} 

的数据源是如下:

public static Dictionary<string, string> TestFiles{ 
    get 
    { 
     return new Dictionary<string, string>() 
      { 
       {".txt", 
       "C:\\test\\test1.txt"}, 
       {".txt", 
       "c:\\test\\test2.txt"} 
      }; 
    } 
} 

我终于制定了使用次重复选项犀牛,是真的很简单:

[Test] 
public void Cpy_Files_ShouldCopyAllFilesInDictionary(){ 
    // Arrange 
    var mockObject = MockRepository.GenerateMock<IFileSystemIO>(); 
    var systemUnderTest = new CopyFileToDestination(mockObject); 

    // Act 
    systemUnderTest.Cpy_Files(dictionary); 

    // Assert 

    // I know how many objects are in my fake dictionary so I set the times to repeat as a const 
    const int timesToRepeat = 2; 

    // now I just set the values below. I am not testing file names so the test will ignore arguments 
    mockObject.AssertWasCalled(f => f.Copy("",""), options => options.Repeat.Times(timesToRepeat).IgnoreArguments()); 
} 

我希望这可以帮助其他人有类似的问题。

+0

你不能在'options.Repeat.Times'中使用'dictionary.Count'吗?我也会倾向于对字典的“foreach”。那就是你实际上可以对字典中的每个项目单独进行断言(如果你需要文件名,这将是要走的路)。 – 2014-01-28 21:29:08

+0

是的,我本可以使用dictionary.Count,但我没有想到这一点。我的偏好是保持单元测试尽可能少的断言,所以我倾向于避免在循环内使用断言。在我看来,在这种情况下断言这个电话已经足够了 – crunchy 2014-01-29 15:44:08

+0

我也试图遵循这个规则,并且考虑一个循环内的断言仍然是“一个断言”......也许我在作弊一点,嘿嘿:P – 2014-01-29 16:56:42

0

我会尝试利用该TestCase属性:

[TestCase(".txt", "c:\test\file1.txt")] 
[TestCase(".txt", "c:\test\file2.txt")] 
[TestCase(".dat", "c:\test\file1.dat")] 
[TestCase(".dat", "c:\test\file2.dat")] 
public void Should_Copy_Text_Files(string extension, string fileName){ 
    var dictionary = new FakeDictionary().FakeFiles(); 
    var mockObject = MockRepository.GenerateMock<IFileSystemIO>(); 
    var systemUnderTest = new CopyFileToDestination(mockObject); 

    systemUnderTest.Cpy_Files(dictionary); 

    mockObject.AssertWasCalled(f => f.Copy(extension, fileName)); 
} 

这将分别运行测试每个TestCase属性,通过它包含的参数到测试方法。通过这种方式,您可以测试字典中的每个项目在相同测试中“复制”而不使用多个声明。

+0

不幸的是,这并没有为我工作。我必须测试的实际文件类型数量使得每个测试用例过于繁琐。 – crunchy 2012-01-06 13:00:01