【问题标题】:What are good ways to unit test interaction with the filesystem?单元测试与文件系统交互的好方法是什么?
【发布时间】:2013-07-03 19:17:50
【问题描述】:

我正在做一个简单的项目,更多的是作为 TDD 的练习而不是其他任何事情。该程序从 Web 服务器获取一些图像并将它们保存为文件。作为记录,我正在做的事情(我想要的最终结果)与this perl script 非常相似,但在 C# 中。

我已经到了需要将文件保存到磁盘的地步。我需要进行单元测试来强制执行代码。我不知道如何解决这个问题。我希望能够验证代码是否使用预期的文件名创建了预期的文件,当然我根本不想接触文件系统。我对单元测试和 TDD 并不是完全陌生,但出于某种原因,我真的不清楚在这种情况下该怎么做。我敢肯定,一旦我看到它,答案就会很明显,但是......我大脑中代码来源的神秘地方就是不合作。

我选择的工具是 MSpec 和 FakeItEasy,但我们将不胜感激地接受任何框架中的建议。对文件系统交互进行单元测试的明智方法是什么?

【问题讨论】:

  • 查看这个问题的公认答案:link
  • 一旦你离开你正在测试的单个类,它就不再是一个单元测试——它是一个集成测试。下面奥利弗的好例子解释了如何保持单元测试,即你测试类的意图,而不是实现:“我想告诉文件持久化器持久化一个文件。我不在乎它是如何做到的。持久化类将单独测试”。如果要检查文件是否真正创建,请编写集成测试。这些测试跨越类,访问文件系统非常好。
  • @dskh 感谢您的评论。我相信我确实提到过我不想在这些测试中触及文件系统。我正在做一个 TDD 练习,所以这绝对是我想要的单元测试。

标签: c# unit-testing tdd


【解决方案1】:

在这里有帮助的是依赖注入。将单体下载操作分解成更小的部分并将它们注入下载器。为这些部分声明接口:

public interface IImageFetcher
{
    IEnumerable<Image> FetchImages(string address);
}

public interface IImagePersistor
{
    void StoreImage(Image image, string path);
}

通过这些声明,您可以编写一个集成整个内容的下载器类,如下所示:

public class ImageDownloader
{
    private IImageFetcher _imageFetcher;
    private IImagePersistor _imagePersistor;

    // Constructor injection of components
    public ImageDownloader(IImageFetcher imageFetcher, IImagePersistor imagePersistor)
    {
        _imageFetcher = imageFetcher;
        _imagePersistor = imagePersistor;
    }

    public void Download(string source, string destination)
    {
        var images = _imageFetcher.FetchImages(source);
        int i = 1;
        foreach (Image img in images) {
            string path = Path.Combine(destination, "Image" + i.ToString("000"));
            _imagePersistor.StoreImage(img, path);
            i++;
        }
    }
}

请注意,ImageDownloader 不知道将使用哪些实现以及它们如何工作。

现在,您可以在测试时提供一个虚拟持久化器,例如将文件名存储在 List&lt;string&gt; 中,而不是提供存储到文件系统的真实持久化器。


更新

// For testing purposes only.
class DummyImagePersistor
{
    public readonly List<string> Filenames = new List<string>();

    public void StoreImage(Image image, string path)
    {
        Filenames.Add(path);
    }
}

测试:

var persistor = new DummyImagePersistor();
var sut = new ImageDownloader(new ImageFetcher(), persistor);
sut.Download("http://myimages.com/images", "C:\Destination");
Assert.AreEqual(10, persistor.Filenames.Count);
...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-09
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-26
    相关资源
    最近更新 更多