c# - 对使用文件系统的类进行单元测试

标签 c# .net unit-testing stream class-design

我有一个输出简单报告文件的类。它从 XML 文件中读取一些记录 ID 号:每个用于查找存储在数据库中的匹配记录。然后它会将每条记录的详细信息写入 CSV 文件。

我想知道 - 组织它的最佳方式是什么,以便易于测试,同时遵循封装原则?我认为除非绝对必要,否则最好避免与文件系统交互,因此我正在处理 Stream 对象。在进行单元测试时,我可以使用部分模拟对象来覆盖读取或写入文件的位。

我也不确定何时何地处理流而不会使单元测试变得棘手。看起来我可能必须将流公开给单元测试。

我的项目使用 NHibernate 进行数据访问,使用 Spring .NET 进行依赖注入(inject),并使用 Rhino.Mocks 进行单元测试。

目前我有类似的东西:

public class ReportBiz
{
    //Access to repository, populated by Spring
    internal ICardRequestDAO CardRequestData { get;set;} 

    //This normally returns a FileStream containing data from the XML file. When testing this is overridden by using a Rhino.Mocks partial mock and returns a MemoryStream
    internal virtual Stream GetSourceStream()
    {
        //Load file and return a Stream
        ...
    }

    //This normally returns a FileStream where CSV data is saved. When testing this is overridden by using a Rhino.Mocks partial mock and returns a MemoryStream
    internal virtual Stream GetOutputStream()
    {
        //Create file where CSV data gets saved and return a Stream
        ...
    }

    public void CreateReportFile()
    {
        Stream sourceStream = GetSourceStream();
        ...

        //Create an XmlDocument instance using the stream
        //For each XML element, get the corresponding record from the database
        //Add record data to CSV stream     
        ...
    }
    }

使用某种自定义工厂或其他东西并将流传递给构造函数会更好吗?但是如果涉及一些业务逻辑呢?文件名是根据查询结果确定的?

或者整个文件访问毕竟不是问题?

如果我遗漏了一些明显的东西,我深表歉意。如果有任何建议,我将不胜感激。

最佳答案

在保留对一次性资源生命周期的控制的同时,使文件访问可模拟的最简单方法是将 StreamFactory 注入(inject)到您的类中:

public class ReportBiz {

    private IStreamFactory streamFactory;

    public ReportBiz(IStreamFactory streamFactory) {
        this.streamFactory = streamFactory
    }

    public void CreateReportFile() {
        using(Stream stream = this.streamFactory.CreateStream()) {
            // perform the important work!
        }
    }
}

当涉及更多的业务逻辑时,您的工厂方法可能会更复杂一些,但不会太多:

public void CreateReportFile() {
    string sourcePath   = this.otherComponent.GetReportPath();
    using(Stream stream = this.streamFactory.CreateStream(sourcePath)) {
        // perform the important work!
    }
}

关于c# - 对使用文件系统的类进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2245905/

相关文章:

django - 在 Django 单元测试中加载固定装置

c# - Threading.SpinWait 结构与 Thread.SpinWait 方法

C# 委托(delegate)回调的奇怪行为

c# - 如何在不使用浏览器控件的情况下检测网页的高度

c# - 在 IE 中托管时在 .NET 中创建的 ActiveX 控件不接收键盘事件

c++ - 如何将字符串中的数据放入cin

c# - 我可以让 NUnit 以随机顺序执行测试吗?

c# - 将值传递给 Controller ​​操作

c# - 如何修复服务器错误 '/' 应用程序?

.net - 矢量化图像