单元测试文件读取功能

时间:2014-03-04 20:36:39

标签: c# unit-testing

我目前的代码如下:

public class SerializeFileHandler
{
    public void WriteListToFile(MyProject myProject, string filePath)
    {
        FileStream outFile;
        BinaryFormatter bFormatter = new BinaryFormatter();

        outFile = new FileStream(filePath, FileMode.Create, FileAccess.Write);

        bFormatter.Serialize(outFile, myProject);

        // Close file
        outFile.Close();
    }

    public MyProject ReadListFromFile(String filePath)
    {
        FileStream inFile;
        BinaryFormatter bFormatter = new BinaryFormatter(); 
        MyProject myProject = new MyProject();

        // Open file for input
        inFile = new FileStream(filePath, FileMode.Open, FileAccess.Read);

        // Obtain objects from file via serialization
        myProject = (MyProject)bFormatter.Deserialize(inFile);

        inFile.Close();
        return myProject;
     }
}

要保存数据文件,我使用public const string myProjectFile = "myproject.dat";,然后当用户单击“保存”按钮时,将任何新数据保存到文件中。当然,我会在括号中使用参数serializeFileHandler.WriteListToFile();

我想要做的是编写单元测试或多个测试,以便在将数据文件读入应用程序方面测试功能。目前,程序加载时会自动加载数据文件(只需ReadListFromFile上的serializeFileHandler

我已经在Visual Studio中使用测试向导创建了测试,但我不确定如何构建测试来自动测试文件读取功能。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:0)

如果是我,我会有一个ReadListFromStream方法,然后我将测试流注入到chcek中,myProject已正确加载。

从文件中测试 我存根ReadListFromStream,只需确保ReadListFromFile调用它。

答案 1 :(得分:0)

SerializeFileHandler目前的问题是它依赖FileStream,后者又将其与文件系统的读取联系起来;为了当前为它编写测试,我们实际上需要与文件系统进行交互。

我们可以通过引入测试接缝来打破对文件系统的依赖,这将允许我们模拟/存根/伪造FileStream的行为。在生产系统中,我们会通过SerializeFileHandler一个FileStream来使用,但在单元测试中,我们会传递一些符合FileStream SerializeFileHandler接口的内容。 1}}正在使用,但允许我们控制行为以进行测试。

首先,我们可以为与文件系统交互的流引入接口

public interface IFileStreamSource
{
   Stream Open(string path, FileMode mode, FileAccess access, FileShare share);
}

SerializeFileHandler依赖于此

public class SerializeFileHandler
{  
    private readonly IFileStreamSource _source;

    public SerializeFileHandler(IFileStreamSource source)
    {
        _source = source;
    }


    public void WriteListToFile(MyProject myProject, string filePath)
    {
        using (var stream = _source.Open(filePath, FileMode.Create, FileAccess.Write)
        {
            BinaryFormatter bFormatter = new BinaryFormatter();
            bFormatter.Serialize(stream, myProject);
        }
    }

    public MyProject ReadListFromFile(String filePath)
    {
        MyProject myProject = null;

        using (var stream = _source.Open(filePath, FileMode.Open, FileAccess.Read))
        {
            BinaryFormatter bFormatter = new BinaryFormatter(); 

            // Obtain objects from file via serialization
            myProject = (MyProject)bFormatter.Deserialize(stream);
        }

        return myProject;
     }
}

现在,您可以使用模拟库(例如Moq)在单元测试中创建Mock<IFileStreamSource>(),可能会返回MemoryStream,并设置Open()时间的预期叫做。

在您的生产代码中,您可能决定为SerializeFileHandler创建一个无参数构造函数,该构造函数将IFileStreamSource的实例传递给带有IFileStreamSource的构造函数,该构造函数将返回一个实例调用FileStreamOpen()的{​​{1}}(la "Poor Man's Dependency Injection"),或者您可能已经在使用IoC / Dependency Injection容器,在这种情况下,您只需为{IFileStreamSource注册组件{1}}服务。

查看当前的代码,我可以看到一些未在ReadListFromFile中处理的情况,例如文件是否存在或文件是否存在但无法反序列化为{{1}的实例}}。您可能希望为案例编写测试并相应地更新代码:)

答案 2 :(得分:0)

如果您需要测试与文件系统交互,可以像其他建议一样创建模拟文件系统包装,或者创建测试可以使用的隔离文件系统。我更喜欢第二种方法,因为测试与现实更相似。

在运行测试之前,设置一个包含测试所需文件的文件夹。然后让测试中的代码访问该文件夹,而不是实际代码访问的文件夹。这样,您可以读取文件,测试代码在缺少文件时的工作方式,以及测试文件创建。