C# Directory.GetFiles的单元测试条件

C# Directory.GetFiles的单元测试条件,c#,unit-testing,C#,Unit Testing,我以前从未使用过单元测试,但我想继续这样做。现在我有一个最简单的方法要测试: public void GetAvailableFiles(string rootFolder) { string[] dirs = Directory.GetFiles(rootFolder); } 我的单元测试如下所示: [Test] public void CheckDirectory() { AvailableFile fileUpload = new AvailableFile();

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

public void GetAvailableFiles(string rootFolder)
{
   string[] dirs = Directory.GetFiles(rootFolder);
}
我的单元测试如下所示:

[Test]
public void CheckDirectory()
{     
   AvailableFile fileUpload = new AvailableFile();
   fileUpload.GetAvailableFiles("C:\\Input");      
}
调试时,我返回目标位置中的所有文件。然而,我正在努力找到一个有效的条件,在这个条件下,这个测试可以验证它是否通过了

我的想法是为这次测试准备一个预期的文件数。我有10个文件在那里,所以我应该期待10个结果回来。然而,我不确定如何用我所拥有的来写这篇文章


我该怎么做

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

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);
}
公共接口IFileScanner{
列出GetAvailableFile(字符串文件夹);
}
[测试]
public void GetAvailableFiles\u EmptyFolder\u ReturnsEmptyList()
{     
//安排
IFileScanner scanner=新文件CanneRemptyFoldersTub();
//表演
var list=scanner.GetAvailableFiles(“伪参数”);
//断言
Assert.IsTrue(list.Count==0);
}

在编写单元测试之前,我建议您阅读《带示例的单元测试艺术》(Roy Osherove)一书中的一些理论。

为该方法提供一些临时目录,其中包含一些文件:

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);
    }
}
此测试速度快,不需要任何依赖项,因此,虽然它不是严格意义上的单元测试,但它没有许多通常与集成测试相关的缺点(依赖外部数据库等)


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

测试中的目标方法与静态实现问题紧密耦合(
目录

假设目标是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容器中注册

完成所有解耦后,您现在可以单独测试依赖于这些服务的实现。您确实希望测试您控制的代码,而不是实现,这就是
目录
。微软会对此进行充分的测试

使用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();
}
[测试]
public void CheckDirectory_Should_GetFiles(){
//安排
var files=new[]{
“假路径1”,
“假路径2”,
//假路径n
};
var rootPath=“C:\\Input”;
var service=newmock();
service.Setup(=>u.GetFiles(rootPath).Returns(files).Verifiable();
var fileUpload=新的可用文件(service.Object);
//表演
fileUpload.GetAvailableFiles(根路径);
//断言
service.Verify();
}

您的测试设置可以,用一堆已知名称的空文件填充它,在该目录上运行
GetAvailableFiles
,验证并清理/删除临时目录。也就是说,这可能是一种人为的场景;基本上测试
目录。GetFiles
是否正常工作似乎没有多大用处(另外,您不会返回或处理
字符串[]dirs
结果,并且该方法无效。您可能希望它返回它们或公开您获得的文件列表。这可能只是一个输入错误。)@N0xus我认为这是一个太复杂的话题,无法在这里讨论。请参阅我在回答中建议你的那本书。目前,你可以按照Chris Sinclair的意见来移动onI,也可以考虑“嘲弄”@opewix所以要测试一个非常简单的方法,我需要编写过于复杂的测试方法?如果你想遵循单元测试的理念,这似乎是一种奇怪的方式。但是你现在可能不需要它。只要尽可能编写测试。任何测试都比什么都好。看起来是这样的!但只有你编写的单元测试代码,没有意义测试
Directory.GetFiles()
,因为它不是您的代码,所以您必须假设它可以工作(我想MS单元已经测试过了)。我对DateTime做了完全相同的事情,以便能够模拟DateTime。现在,设置测试中需要的任何时间。