Search code examples
c#autofixture

Using AutoFixture to create MockFileSystem and its corresponding types


I'm using AutoFixture to test some code that uses System.IO.Abstractions.IFileSystem.

I also have some code that uses IFileInfo and IDirectoryInfo. When I create my AutoFixture Fixture object, I need to accomplish a couple of things:

  1. I need all IFileSystem parameters to be automatically given a frozen (singleton) instance of MockFileSystem.
  2. All IFileInfo instances need to originate from MockFileSystem via MockFileSystem.FileInfo.FromFileName() somehow. If there's a way to take an existing IFileInfo that AutoFixture created and replace it, I can use the FullName property to pass to MockFileSystem so that it's connected to that instance.
  3. Similar to the previous point, I need IDirectoryInfo instances to originate from MockFileSystem.

I personally find the AutoFixture customization system very confusing and lacks proper documentation. There's pieces of information out there but I'm not sure how to accomplish my goals.


Solution

  • As I struggled through solving my own problem, I eventually came up with this class:

    public class MockFileSystemSpecimenBuilder : ICustomization
    {
        public void Customize(IFixture fixture)
        {
            var fs = new MockFileSystem();
            fixture.Inject(fs);
    
            fixture.Customize<IFileInfo>(x => x.FromFactory(() =>
            {
                var name = $"MockFile-{fixture.Create<string>()}";
                return fs.CurrentDirectory().File(name);
            }));
    
            fixture.Customize<IDirectoryInfo>(x => x.FromFactory(() =>
            {
                var name = $"MockDirectory-{fixture.Create<string>()}";
                return fs.CurrentDirectory().SubDirectory(name);
            }));
        }
    }
    

    I add it to my Fixture class after its created in my factory method:

    public static Fixture Create()
    {
        var fixture = new Fixture
        {
            OmitAutoProperties = true
        };
    
        fixture
            .Customize(new AutoNSubstituteCustomization {ConfigureMembers = true})
            .Customize(new MockFileSystemSpecimenBuilder());
    
        return fixture;
    }
    

    One thing I really enjoy about this solution is that I do not need to explicitly Freeze() the IFileSystem type anymore. The mock filesystem is intrinsic to this fixture so I always get correct file system behavior. This ends up being less error prone and more convenient.