user584018
user584018

Reputation: 11364

Directory not found while unit testing

When I execute my test case, it fails for path within my machine which doesn't exist and I am getting below error:

System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Data1'.

Do I need some kind of fake/mock here to pass the test case or do we have other way to do this?

Class

public class DemoCls
{
    public void Execute()
    {
        string dataFolder = @"C:\\Data1";
        foreach (string X in Directory.EnumerateFiles(dataFolder, "test" + "*.xml"))
        {
        }
    }
}

Test Case

[TestClass()]
public class DemoClsTests
{
    [TestMethod()]
    public void ExecuteTest()
    {
        var X = new DemoCls();
        X.Execute();
    }
}

Upvotes: 1

Views: 3886

Answers (2)

Nkosi
Nkosi

Reputation: 247471

Class should be refactored to remove tight coupling to implementation concerns that make it difficult to test.

//...Creat an abstraction that provides the desired behavior as a contract
public interface IDirectoryService {
    IEnumerable<string> EnumerateFiles(string path, string searchPattern);
}

A fake/mock can be created for when testing to avoid pitfalls associated with testing IO code in isolation.

A mocking framework could have been used for stubbing the dependencies, but for this example using a simple

public class FakeDIrectoryService : IDirectoryService {
    IEnumerable<string> files;
    public FakeDIrectoryService(IEnumerable<string> files) {
        this.files = files;
    }
    public IEnumerable<string> EnumerateFiles(string path, string searchPattern = null) {
        return files;
    }
}

Class needs to be refactored now to follow Explicit Dependencies Principle via constructor and method injection.

public class DemoCls {
    IDirectoryService directory;
    public DemoCls(IDirectoryService directory) {
        this.directory = directory;
    }

    public void Execute(string dataFolder) {
        foreach (var x in directory.EnumerateFiles(dataFolder, "test*.xml")) {
            //...
        }
    }
}

Test can now be properly exercised in isolation.

[TestClass()]
public class DemoClsTests {
    [TestMethod()]
    public void ExecuteTest() {
        //Arrange
        var fakePath = "C:/temp";
        var fakeFiles = new[] { 
            @"C:\\temp\\testfakefilename1.txt", 
            @"C:\\temp\\testfakefilename2.txt",
            @"C:\\temp\\testfakefilename3.txt" 
        };
        var service = new FakeDIrectoryService(fakeFiles);
        var sut = new DemoCls(service);

        //Act
        sut.Execute(fakePath);

        //Assert
        //perform your assertions
    }
}

Finally for production code the real implementation of the file service can wrap any source, be it disk or remote service.

For example

public class FileService : IDirectoryService {
    public IEnumerable<string> EnumerateFiles(string path, string searchPattern) {
        return Directory.EnumerateFiles(path, searchPattern);
    }
}

This is just an example of what can be done. There is a lot of room for improvement but this should get things started.

Upvotes: 3

robjam
robjam

Reputation: 989

Hardcoded paths are not good to have and I would recommend two options since the class is not static.

1st

public class DemoCls
{
    public void Execute(string targetPath)
    {
        foreach (string X in Directory.EnumerateFiles(targetPath, "test" + "*.xml"))
        {
        }
    }
}

This keeps things more flexible and reusable

2nd

public class DemoCls
{
    private string _targetPath;

    public DemoCls(string targetPath){
        _targetPath = targetPath;
    }
    public void Execute(string targetPath)
    {
        foreach (string X in Directory.EnumerateFiles(targetPath, "test" + "*.xml"))
        {
        }
    }
}

This way keeps the Execute method cleaner (less preferred)

Upvotes: 0

Related Questions