2012-01-05 113 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