【问题标题】:Unit Testing Conditions for Directory.GetFilesDirectory.GetFiles 的单元测试条件
【发布时间】:2017-07-20 14:00:28
【问题描述】:

我以前从未使用过单元测试,但我希望继续这样做。现在我有我想测试的最简单的方法:

public void GetAvailableFiles(string rootFolder)
{
   string[] dirs = Directory.GetFiles(rootFolder);
}

我对此的单元测试如下:

[Test]
public void CheckDirectory()
{     
   AvailableFile fileUpload = new AvailableFile();
   fileUpload.GetAvailableFiles("C:\\Input");      
}

当我调试它时,我会返回目标位置中的所有文件。但是,我正在努力想出一个有效的条件,在这个条件下,这个测试可以验证它已经通过了。

我的想法是为此测试提供预期的文件数。我有 10 个文件,所以我应该期待 10 个结果。但是,我不确定如何用我所拥有的东西来写这篇文章。

我应该怎么做?

【问题讨论】:

  • 您的测试设置可以create a temp directory,用一堆已知名称的空文件填充它,在该目录上运行您的GetAvailableFiles,验证并清理/删除临时目录。也就是说,这可能是一个人为的场景。从本质上测试Directory.GetFiles 是否有效似乎并不是非常有用。 (此外,您不会返回或对 string[] dirs 结果执行任何操作,并且该方法是无效的。您可能希望它返回它们或公开您获得的文件列表。也许这只是一个错字。)

标签: c# unit-testing


【解决方案1】:

这不是单元测试。这是一个集成测试,因为您与文件系统交互。如果要进行单元测试,则必须将文件系统交互提取到接口中。例如:

public interface IFileScanner {
   List<string> GetAvailableFiles(string folder);
}

[Test]
public void GetAvailableFiles_EmptyFolder_ReturnsEmptyList()
{     
   // Arrange
   IFileScanner scanner = new FileScannerEmptyFolderStub();

   // Act
   var list = scanner.GetAvailableFiles("dummy argument");

   // Assert
   Assert.IsTrue(list.Count == 0);
}

我建议您在编写单元测试之前阅读The art of unit testing with examples (Roy Osherove) 中的一些理论。

【讨论】:

  • @N0xus 我认为这里讨论的话题太复杂了。请参阅我在回答中建议您的书。目前,您可以关注Chris Sinclair评论继续前进
  • 我也建议,看看“嘲笑”。
  • @opewix 所以要测试一个非常简单的方法我需要编写过于复杂的测试方法吗?这似乎是一种奇怪的处理方式
  • 是的,如果你想遵循单元测试的想法。但你现在可能不需要它。尽可能地编写测试。有测试总比没有好
  • 看起来是这样的!但只有您编写的单元测试代码,没有意义测试 Directory.GetFiles() 因为它不是您的代码,您必须假设它有效(我想认为 MS 单元测试已经)。
【解决方案2】:

被测目标方法与静态实现问题紧密耦合 (Directory)。

所以假设一个目标 SUT

public class AvailableFile {
    public void GetAvailableFiles(string rootFolder) {
       string[] files = Directory.GetFiles(rootFolder);
       //...other code using files
    }
}

将其提取到明确的服务依赖项中。

public interface IDirectory {
    string[] GetFiles(string rootFolder);
}

并重构 SUT

public class AvailableFile {
    private readonly IDirectory directory;

    public AvailableFile (IDirectory directory) {
        this.directory = directory;
    }

    public void GetAvailableFiles(string rootFolder) {
       string[] files = directory.GetFiles(rootFolder);
       //...other code using files
    }
}

服务的实现可以像这样

public class DirectoryServie : IDirectory  {
    public string[] GetFiles(string rootFolder) {
        return Directory.GetFiles(rootFolder);
    }
}

确保接口和实现已在您的组合根目录中注册到您的 IoC 容器。

完成所有解耦后,您现在可以单独测试依赖于这些服务的实现。你真的想测试你控制的代码,而不是第三部分的实现,这就是Directory。微软会对此进行足够好的测试。

使用 Moq,您可以单独测试您的目标系统,而无需考虑任何实施问题。

[Test]
public void CheckDirectory_Should_GetFiles() {
    //Arrange
    var files = new [] { 
        "fake path 1",
        "fake path 2",
        //fake path n
    };
    var rootPath = "C:\\Input";
    var service = new Mock<IDirectory>();
    service.Setup(_ => _.GetFiles(rootPath).Returns(files).Verifiable();

    var fileUpload = new AvailableFile(service.Object);

    //Act   
    fileUpload.GetAvailableFiles(rootPath);

    //Assert
    service.Verify();
}

【讨论】:

  • 我对 DateTime 做了完全相同的事情,以便能够模拟 DateTime.Now 并在我的测试中设置我需要的任何时间。
【解决方案3】:

给方法一些临时目录,里面有一些文件:

public class TestClass : IDisposable
{
    private string _directory;

    public TestClass()
    {
        _directory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
        Directory.CreateDirectory(_directory);
    }

    [Fact]
    public void NoFiles()
    {
        Assert.Empty(GetAvailableFiles(_directory));
    }

    [Fact]
    public void TwoFiles()
    {
        File.WriteAllText(Path.Combine(_directory, "aaa.txt"), "");
        File.WriteAllText(Path.Combine(_directory, "bbb.txt"), "");

        var files = GetAvailableFiles(_directory);
        Assert.Equal(2, files.Length);
        Assert.Contains(Path.Combine(_directory, "aaa.txt"), files);
        Assert.Contains(Path.Combine(_directory, "bbb.txt"), files);
    }

    public void Dispose()
    {
        Directory.Delete(_directory, true);
    }

    // Method under test
    public string[] GetAvailableFiles(string rootFolder)
    {
        return Directory.GetFiles(rootFolder);
    }
}

这个测试速度很快,不需要任何依赖,因此虽然它不是严格意义上的单元测试,但它并没有很多通常与集成测试相关的缺点(依赖于外部数据库等)。 .)

如果此方法包含大量其他逻辑(例如处理这些文件的内容),那么在该逻辑和文件系统访问之间引入一个接缝是个好主意。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-22
    • 2021-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多