Mocking the File system

One problem with files is that testing can be problematic, what file to use? what path to use? how to test when a file is missing? do I really need another file in my Version Control System? how to simulate 100s of files in one directory?

Sometimes it can be useful to Mock these files, for this you can create an interface IFileSystemProvider, which gives all the classic functions of the System.IO.File class and a FileSystemProvider class, which link all these methods to the actual System.IO.File class. If you do not want to instantiate a class for FileSystemProvider you can also create a static class FileSystem, this class instantiate a File variable as a FileSystemProvider by default and offers also all the methods of IFileSystemProvider. If you do this you can use FileSystem.File as if it was System.IO.File, but also mock its behaviour in your unit tests!

The FileSystem class

using System.Collections.Generic;
using System.IO;

namespace FileMocking
{
    public interface IFileSystemProvider
    {
        bool Exists(string path);
        IEnumerable<string> ReadLines(string path);
    }

    public class FileSystemProvider : IFileSystemProvider
    {
        public bool Exists(string path) => File.Exists(path);
        public IEnumerable<string> ReadLines(string path) => File.ReadLines(path);
    }

    public interface IDirectorySystemProvider
    {
        IEnumerable<string> EnumerateFiles(string path);
        bool Exists(string path);
    }

    public class DirectorySystemProvider : IDirectorySystemProvider
    {
        public IEnumerable<string> EnumerateFiles(string path) => Directory.EnumerateFiles(path);
        public bool Exists(string path) => Directory.Exists(path);
    }

    public static class FileSystem
    {
        public static IFileSystemProvider File = new FileSystemProvider();
        public static IDirectorySystemProvider Directory = new DirectorySystemProvider();
    }
}

Using FileSystem in your application

Since FileSystem is a static class, its usage is very similar to System.IO.File and System.IO.Directory. Here are only a few functions implemented for overview but you should map all the original methods.

using FileMocking;
using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string filePath = @"C:\Users\username\Documents\someDoc.txt";
            string directoryPath = @"C:\Users\username\Documents\";

            if (FileSystem.File.Exists(filePath))
            {
                var lines = FileSystem.File.ReadLines(filePath);

                foreach (string line in lines)
                {
                    Console.WriteLine(line);
                }
            }

            if (FileSystem.Directory.Exists(directoryPath))
            {
                var files = FileSystem.Directory.EnumerateFiles(directoryPath);

                foreach (string file in files)
                {
                    Console.WriteLine(file);
                }
            }

            Console.ReadKey();
        }
    }
}

Mocking the FileSystem

In your unit test you can then easily mock FileSystem.File and FileSystem.Directory with other implementations of the IFileSystemProvider and IDirectorySystemProvider interfaces.

using FileMocking;
using System;

namespace ConsoleApp
{
    public class FileSystemProviderMock : IFileSystemProvider
    {
        public bool Exists(string path)
        {
            return true;
        }

        public IEnumerable<string> ReadLines(string path)
        {
            var lines = new List<string>()
            {
                "line1",
                "line2",
                "line3",
                "line4",
            };

            return lines.ToArray();
        }
    }

    public class DirectorySystemProviderMock : IDirectorySystemProvider
    {
        public IEnumerable<string> EnumerateFiles(string path)
        {
            return new List<string>()
            {
                "file1.abc",
                "file2.abc",
                "file3.abc",
            };
        }

        public bool Exists(string path)
        {
            return true;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Mock your File System!
            FileSystem.File = new FileSystemProviderMock();
            FileSystem.Directory = new DirectorySystemProviderMock();

            string filePath = @"C:\Users\username\Documents\someDoc.txt";
            string directoryPath = @"C:\Users\username\Documents\";

            if (FileSystem.File.Exists(filePath))
            {
                var lines = FileSystem.File.ReadLines(filePath);

                foreach (string line in lines)
                {
                    Console.WriteLine(line);
                }
            }

            if (FileSystem.Directory.Exists(directoryPath))
            {
                var files = FileSystem.Directory.EnumerateFiles(directoryPath);

                foreach (string file in files)
                {
                    Console.WriteLine(file);
                }
            }

            Console.ReadKey();
        }
    }
}

See also

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s