Parallel.ForEach中的Mock方法始终返回null

时间:2016-06-09 18:45:00

标签: c# unit-testing rhino-mocks parallel.foreach

我有以下代码:

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吗?有没有办法做这样的模拟?

如果您需要任何其他信息,请告知我们。

2 个答案:

答案 0 :(得分:3)

我不认为并行化存在问题。看来你的问题与使用Rhino Mock的代理实例设置有关。

确保传入ReadAllLines参数的内容与运行生产代码时调用它们的内容相同。

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

例如,如果您在不同的路径上进行设置,并且在执行测试时该路径的值为diefferent,则可能会看到NULL作为回报。但是在没有看到代码中的完整设置/构造函数的情况下再次很难说。还要检查随机生成器,查看每次使用的内容。

以下是我整理并为我工作。 工作意味着我不会因为:

而获得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();
    }
}

答案 1 :(得分:1)

我可以摆脱这个问题,可能是由于使用随机值造成的。我现在正按照我的期望调用IgnoreArguments()方法:

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

它可以解决问题(即单元测试成功运行),但我不知道它是否非常优雅。