Reputation: 11364
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
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
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