Skip to content

Repository files navigation

System.IO.AbstractionsNuGetContinuous IntegrationCodacy BadgeRenovate enabledFOSSA Status

At the core of the library is IFileSystem and FileSystem. Instead of calling methods like File.ReadAllText directly, use IFileSystem.File.ReadAllText. We have exactly the same API, except that ours is injectable and testable.

dotnet add package System.IO.Abstractions
publicclassMyComponent{readonlyIFileSystemfileSystem;// <summary>Create MyComponent with the given fileSystem implementation</summary>publicMyComponent(IFileSystemfileSystem){this.fileSystem=fileSystem;}/// <summary>Create MyComponent</summary>publicMyComponent():this(fileSystem:newFileSystem()//use default implementation which calls System.IO){}publicvoidValidate(){foreach(vartextFileinfileSystem.Directory.GetFiles(@"c:\","*.txt",SearchOption.TopDirectoryOnly)){vartext=fileSystem.File.ReadAllText(textFile);if(text!="Testing is awesome.")thrownewNotSupportedException("We can't go on together. It's not me, it's you.");}}}

The library also ships with a series of test helpers to save you from having to mock out every call, for basic scenarios. They are not a complete copy of a real-life file system, but they'll get you most of the way there.

dotnet add package System.IO.Abstractions.TestingHelpers
[Test]publicvoidMyComponent_Validate_ShouldThrowNotSupportedExceptionIfTestingIsNotAwesome(){// ArrangevarfileSystem=newMockFileSystem(newDictionary<string,MockFileData>{{@"c:\myfile.txt",newMockFileData("Testing is meh.")},{@"c:\demo\jQuery.js",newMockFileData("some js")},{@"c:\demo\image.gif",newMockFileData(newbyte[]{0x12,0x34,0x56,0xd2})}});varcomponent=newMyComponent(fileSystem);try{// Actcomponent.Validate();}catch(NotSupportedExceptionex){// AssertAssert.AreEqual("We can't go on together. It's not me, it's you.",ex.Message);return;}Assert.Fail("The expected exception was not thrown.");}

We even support casting from the .NET Framework's untestable types to our testable wrappers:

FileInfoSomeApiMethodThatReturnsFileInfo(){returnnewFileInfo("a");}voidMyFancyMethod(){vartestableFileInfo=(FileInfoBase)SomeApiMethodThatReturnsFileInfo();
...}

Since version 4.0 the top-level APIs expose interfaces instead of abstract base classes (these still exist, though), allowing you to completely mock the file system. Here's a small example, using Moq:

[Test]publicvoidTest1(){varwatcher=Mock.Of<IFileSystemWatcher>();varfile=Mock.Of<IFile>();Mock.Get(file).Setup(f =>f.Exists(It.IsAny<string>())).Returns(true);Mock.Get(file).Setup(f =>f.ReadAllText(It.IsAny<string>())).Throws<OutOfMemoryException>();varunitUnderTest=newSomeClassUsingFileSystemWatcher(watcher,file);Assert.Throws<OutOfMemoryException>(()=>{Mock.Get(watcher).Raise(w =>w.Created+=null,newSystem.IO.FileSystemEventArgs(System.IO.WatcherChangeTypes.Created,@"C:\Some\Directory","Some.File"));});Mock.Get(file).Verify(f =>f.Exists(It.IsAny<string>()),Times.Once);Assert.True(unitUnderTest.FileWasCreated);}publicclassSomeClassUsingFileSystemWatcher{privatereadonlyIFileSystemWatcher_watcher;privatereadonlyIFile_file;publicboolFileWasCreated{get;privateset;}publicSomeClassUsingFileSystemWatcher(IFileSystemWatcherwatcher,IFilefile){this._file=file;this._watcher=watcher;this._watcher.Created+=Watcher_Created;}privatevoidWatcher_Created(objectsender,System.IO.FileSystemEventArgse){FileWasCreated=true;if(_file.Exists(e.FullPath)){vartext=_file.ReadAllText(e.FullPath);}}}

About

Just like System.Web.Abstractions, but for System.IO. Yay for testable IO access!

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages