2016-06-09 119 views
3

我有以下代碼:模擬方法始終返回null

public int LoadFilesAndSaveInDatabase(string filesPath) 
{ 
    var calls = new ConcurrentStack<GdsCallDto>(); 

    var filesInDirectory = this._directoryProxy.GetFiles(filesPath); 
    if (filesInDirectory.Any()) 
    { 
     Parallel.ForEach(filesInDirectory, file => 
     { 
      var lines = this._fileProxy.ReadAllLines(file, Encoding.Unicode); 
      if (lines.Any()) 
      { 
       // Reads the file and setup a new DTO. 
       var deserializedCall = this._fileManager.DeserializeFileContent(lines, Path.GetFileName(file)); 

       // Insert the DTO in the database. 
       this._gdsCallsData.InsertOrUpdateGdsCall(deserializedCall); 

       // We keep track of the dto to count the number of restored items. 
       calls.Push(deserializedCall); 
      } 
     }); 
    } 
    return calls.Count; 
} 

我具有以下的單元測試:

[TestMethod] 
public void ShouldLoadFilesAndSaveInDatabase() 
{ 
    // Arrange 
    var path = RandomGenerator.GetRandomString(56); 
    var encoding = Encoding.Unicode; 
    var fileNameEnvironment = RandomGenerator.GetRandomString(); 
    var fileNameModule = RandomGenerator.GetRandomString(); 
    var fileNameRecordLocator = RandomGenerator.GetRandomString(6); 
    var fileNameTimestamp = RandomGenerator.GetRandomDateTime().ToString("O").Replace(':', 'o'); 

    // We simulate the presence of 4 files. 
    var files = new List<string> 
    { 
     RandomGenerator.GetRandomString(255), 
     RandomGenerator.GetRandomString(255), 
     RandomGenerator.GetRandomString(255), 
     RandomGenerator.GetRandomString(255) 
    }.ToArray(); 

    var expectedResult = 4; 

    this._directoryProxy.Expect(d => d.GetFiles(path)) 
     .Return(files); 

    this._fileProxy.Expect(f => f.ReadAllLines(path, encoding)) 
     .Return(files).Repeat.Times(files.Length); 

    // Act 
    var result = this._databaseReloadManager.LoadFilesAndSaveInDatabase(path); 

    // Assert 
    Assert.AreEqual(result, expectedResult); 
    this._directoryProxy.AssertWasCalled(d => d.GetFiles(path)); 
    this._fileProxy.AssertWasCalled(f => f.ReadAllLines(path, Encoding.Unicode)); 
} 

的問題是上下面的行:

var lines = this._fileProxy.ReadAllLines(file, Encoding.Unicode); 

即使我設置了期望和返回值,當我運行單元測試時,它總是返回null。

我正在使用Rhino.Mocks,它在其他地方工作得很好,但沒有。

我在這裏看了一些討論,但沒有一個幫助。這可能是由於使用了Parallel.ForEach嗎?有沒有辦法做這樣的模擬?

如果您需要任何其他信息,請讓我知道。

+0

你有可怕的壞namings那裏。什麼是「_DirectoryProxy」和什麼是「_FileProxy」?您是否期望應用程序能夠讀取不存在的文件? –

+0

@cFrozenDeath,這個命名不是我的責任,它是我們公司框架的一部分。 「代理」類旨在避免直接調用System.IO.File和System.IO.Directory類,以便我們可以模擬它們,並且它們提供了與IO類相同的功能。 – DotNetMatt

回答

1

我可以擺脫這個問題,可能是由使用造成的的隨機值。現在我對我的期望調用方法IgnoreArguments():

this._fileProxy.Expect(f => f.ReadAllLines(path, encoding)) 
    .Return(files).Repeat.Times(files.Length).IgnoreArguments(); 

它做(即單元測試運行成功)的伎倆,但我不知道這是否是非常優雅。

3

我不認爲並行化存在問題。看來你的問題與Rhino Mock的代理實例設置有關。

確保您傳入ReadAllLines參數的內容與通過生產代碼運行時調用它們的內容相同。

this._fileProxy.Expect(f => f.ReadAllLines(path, encoding)) 
     .Return(files).Repeat.Times(files.Length); 

例如,如果你設置不同路徑上,當測試執行,您可以在返回NULL看到這條道路diefferent的價值。但是,如果沒有在代碼中看到完整的設置/構造函數,也很難分辨出來。同時檢查隨機生成器,看看每次都使用了什麼。

以下是我整理和爲我工作。 工作意味着我不爲NULL得到:

var lines = this._fileProxy.ReadAllLines(file, Encoding.Unicode); 

//some dummy code so I can compile 
public interface IProxyDir 
{ 
    IEnumerable<string> GetFiles(string path); 
} 

public class GdsCallDto 
{ 
} 

public class Proxy : IProxyDir 
{ 
    public IEnumerable<string> GetFiles(string path) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public interface IFileDir 
{ 
    IEnumerable<string> ReadAllLines(string path, Encoding encoding); 
} 

public class FileProxy : IFileDir 
{ 
    public IEnumerable<string> ReadAllLines(string path, Encoding encoding) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public interface IFileMgr 
{ 
    string DeserializeFileContent(IEnumerable<string> lines, string content); 
} 

public class FileMgr : IFileMgr 
{ 
    public string DeserializeFileContent(IEnumerable<string> lines, string content) 
    { 
     throw new NotImplementedException(); 
    } 
} 

//system under test 
public class Sut 
{ 
    private IProxyDir _directoryProxy; 
    private IFileDir _fileProxy; 
    private IFileMgr _fileManager; 

    public Sut(IProxyDir proxyDir, IFileDir fileProxy, IFileMgr mgr) 
    { 
     _fileManager = mgr; 
     _directoryProxy = proxyDir; 
     _fileProxy = fileProxy; 
    } 

    public int LoadFilesAndSaveInDatabase(string filesPath) 
    { 
     var calls = new ConcurrentStack<GdsCallDto>(); 

     var filesInDirectory = this._directoryProxy.GetFiles(filesPath); 
     if (filesInDirectory.Any()) 
     { 
      Parallel.ForEach(filesInDirectory, file => 
      { 
       var lines = this._fileProxy.ReadAllLines("ssss", Encoding.Unicode); 

       if (lines.Any()) 
       { 
        // Reads the file and setup a new DTO. 
        var deserializedCall = this._fileManager.DeserializeFileContent(lines, Path.GetFileName("file")); 

        // Insert the DTO in the database. 
        //this._gdsCallsData.InsertOrUpdateGdsCall(deserializedCall); 

        // We keep track of the dto to count the number of restored items. 
        //calls.Push(deserializedCall); 
       } 
      }); 
     } 

     return 1; 
    } 
} 

樣本單位測試

[TestClass] 
public class UnitTest1 
{ 
    private IProxyDir _directoryProxy; 
    private IFileDir _fileProxy; 
    private IFileMgr _fileMgr; 

    private Sut _sut; 

    public UnitTest1() 
    { 
     _directoryProxy = MockRepository.GenerateMock<IProxyDir>(); 
     _fileProxy = MockRepository.GenerateMock<IFileDir>(); 
     _fileMgr = MockRepository.GenerateMock<IFileMgr>(); 
    } 

    [TestMethod] 
    public void ShouldLoadFilesAndSaveInDatabase() 
    { 
     // Arrange 
     var path = RandomGenerator.GetRandomString(56); 
     var encoding = Encoding.Unicode; 
     var fileNameEnvironment = RandomGenerator.GetRandomString(5); 
     var fileNameModule = RandomGenerator.GetRandomString(5); 
     var fileNameRecordLocator = RandomGenerator.GetRandomString(6); 
     var fileNameTimestamp = RandomGenerator.GetRandomDateTime().ToString("O").Replace(':', 'o'); 

     // We simulate the presence of 4 files. 
     var files = new List<string> 
     { 
      RandomGenerator.GetRandomString(255), 
      RandomGenerator.GetRandomString(255), 
      RandomGenerator.GetRandomString(255), 
      RandomGenerator.GetRandomString(255) 
     }.ToArray(); 

     var expectedResult = 4; 

     this._directoryProxy.Expect(d => d.GetFiles(path)) 
      .Return(files); 

     this._fileProxy.Expect(f => f.ReadAllLines(path, encoding)) 
    .Return(files).Repeat.Times(files.Length); 

     _sut = new Sut(_directoryProxy, _fileProxy, _fileMgr); 

     // Act 
     var result = this._sut.LoadFilesAndSaveInDatabase(path); 

     // Assert 
     Assert.AreEqual(result, expectedResult); 
     this._directoryProxy.AssertWasCalled(d => d.GetFiles(path)); 
     this._fileProxy.AssertWasCalled(f => f.ReadAllLines(path, Encoding.Unicode)); 
    } 

} 

internal class RandomGenerator 
{ 
    public static string GetRandomString(int number) 
    { 
     return "ssss"; 
    } 

    public static DateTime GetRandomDateTime() 
    { 
     return new DateTime(); 
    } 
} 
+0

我認爲你的代碼工作原理是因爲你刪除了隨機生成器的「隨機性」,但你的代碼和我的一樣。所以這並沒有幫助。我可以通過在期望中使用方法IgnoreArguments()來擺脫這個問題。 – DotNetMatt

+0

合理感謝:) – Spock