Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 54 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ and/or:

Install-Package System.IO.Abstractions.TestingHelpers

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.
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.

```csharp
public class MyComponent
Expand All @@ -28,7 +28,7 @@ public class MyComponent
/// <summary>Create MyComponent</summary>
public MyComponent() : this(
fileSystem: new FileSystem() //use default implementation which calls System.IO
)
)
{
}

Expand Down Expand Up @@ -74,17 +74,67 @@ public void MyComponent_Validate_ShouldThrowNotSupportedExceptionIfTestingIsNotA
Assert.Fail("The expected exception was not thrown.");
}
```

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

```csharp
FileInfo SomeBadApiMethodThatReturnsFileInfo()
FileInfo SomeApiMethodThatReturnsFileInfo()
{
return new FileInfo("a");
}

void MyFancyMethod()
{
var testableFileInfo = (FileInfoBase)SomeBadApiMethodThatReturnsFileInfo();
var testableFileInfo = (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](https://github.com/moq/moq4):

```csharp
[Test]
public void Test1()
{
var watcher = Mock.Of<IFileSystemWatcher>();
var file = 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>();

var unitUnderTest = new SomeClassUsingFileSystemWatcher(watcher, file);

Assert.Throws<OutOfMemoryException>(() => {
Mock.Get(watcher).Raise(w => w.Created += null, new System.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);
}

public class SomeClassUsingFileSystemWatcher
{
private readonly IFileSystemWatcher _watcher;
private readonly IFile _file;

public bool FileWasCreated { get; private set; }

public SomeClassUsingFileSystemWatcher(IFileSystemWatcher watcher, IFile file)
{
this._file = file;
this._watcher = watcher;
this._watcher.Created += Watcher_Created;
}

private void Watcher_Created(object sender, System.IO.FileSystemEventArgs e)
{
FileWasCreated = true;

if(_file.Exists(e.FullPath))
{
var text = _file.ReadAllText(e.FullPath);
}
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace System.IO.Abstractions.TestingHelpers.Tests
{
public class MockDirectoryArgumentPathTests
{
private static IEnumerable<Action<DirectoryBase>> GetFileSystemActionsForArgumentNullException()
private static IEnumerable<Action<IDirectory>> GetFileSystemActionsForArgumentNullException()
{
yield return ds => ds.Delete(null);
yield return ds => ds.Delete(null, true);
Expand All @@ -26,7 +26,7 @@ private static IEnumerable<Action<DirectoryBase>> GetFileSystemActionsForArgumen
}

[TestCaseSource("GetFileSystemActionsForArgumentNullException")]
public void Operations_ShouldThrowArgumentNullExceptionIfPathIsNull(Action<DirectoryBase> action)
public void Operations_ShouldThrowArgumentNullExceptionIfPathIsNull(Action<IDirectory> action)
{
// Arrange
var fileSystem = new MockFileSystem();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace System.IO.Abstractions.TestingHelpers.Tests
{
public class MockFileArgumentPathTests
{
private static IEnumerable<Action<FileBase>> GetFileSystemActionsForArgumentNullException()
private static IEnumerable<Action<IFile>> GetFileSystemActionsForArgumentNullException()
{
yield return fs => fs.AppendAllLines(null, new[] { "does not matter" });
yield return fs => fs.AppendAllLines(null, new[] { "does not matter" }, Encoding.ASCII);
Expand Down Expand Up @@ -57,7 +57,7 @@ private static IEnumerable<Action<FileBase>> GetFileSystemActionsForArgumentNull
}

[TestCaseSource("GetFileSystemActionsForArgumentNullException")]
public void Operations_ShouldThrowArgumentNullExceptionIfPathIsNull(Action<FileBase> action)
public void Operations_ShouldThrowArgumentNullExceptionIfPathIsNull(Action<IFile> action)
{
// Arrange
var fileSystem = new MockFileSystem();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,8 @@ public void MockFileSystem_FileSystemWatcher_ShouldBeAssignable()

private class TestFileSystemWatcherFactory : IFileSystemWatcherFactory
{
public FileSystemWatcherBase CreateNew() => new TestFileSystemWatcher(null);
public FileSystemWatcherBase FromPath(string path) => new TestFileSystemWatcher(path);
public IFileSystemWatcher CreateNew() => new TestFileSystemWatcher(null);
public IFileSystemWatcher FromPath(string path) => new TestFileSystemWatcher(path);
}

private class TestFileSystemWatcher : FileSystemWatcherBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ public interface IMockFileDataAccessor

StringOperations StringOperations { get; }

FileBase File { get; }
DirectoryBase Directory { get; }
IFile File { get; }
IDirectory Directory { get; }
IFileInfoFactory FileInfo {get; }
PathBase Path { get; }
IPath Path { get; }
IDirectoryInfoFactory DirectoryInfo { get; }
IDriveInfoFactory DriveInfo { get; }

Expand Down
8 changes: 4 additions & 4 deletions System.IO.Abstractions.TestingHelpers/MockDirectory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@ public MockDirectory(IMockFileDataAccessor mockFileDataAccessor, string currentD
this.mockFileDataAccessor = mockFileDataAccessor ?? throw new ArgumentNullException(nameof(mockFileDataAccessor));
}

public override DirectoryInfoBase CreateDirectory(string path)
public override IDirectoryInfo CreateDirectory(string path)
{
return CreateDirectoryInternal(path, null);
}

#if NET40
public override DirectoryInfoBase CreateDirectory(string path, DirectorySecurity directorySecurity)
public override IDirectoryInfo CreateDirectory(string path, DirectorySecurity directorySecurity)
{
return CreateDirectoryInternal(path, directorySecurity);
}
#endif

private DirectoryInfoBase CreateDirectoryInternal(string path, DirectorySecurity directorySecurity)
private IDirectoryInfo CreateDirectoryInternal(string path, DirectorySecurity directorySecurity)
{
if (path == null)
{
Expand Down Expand Up @@ -312,7 +312,7 @@ public override string[] GetLogicalDrives()
}
#endif

public override DirectoryInfoBase GetParent(string path)
public override IDirectoryInfo GetParent(string path)
{
if (path == null)
{
Expand Down
48 changes: 24 additions & 24 deletions System.IO.Abstractions.TestingHelpers/MockDirectoryInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,13 @@ public override void Create(DirectorySecurity directorySecurity)
}
#endif

public override DirectoryInfoBase CreateSubdirectory(string path)
public override IDirectoryInfo CreateSubdirectory(string path)
{
return mockFileDataAccessor.Directory.CreateDirectory(Path.Combine(FullName, path));
}

#if NET40
public override DirectoryInfoBase CreateSubdirectory(string path, DirectorySecurity directorySecurity)
public override IDirectoryInfo CreateSubdirectory(string path, DirectorySecurity directorySecurity)
{
return mockFileDataAccessor.Directory.CreateDirectory(Path.Combine(FullName, path), directorySecurity);
}
Expand All @@ -144,47 +144,47 @@ public override void Delete(bool recursive)
mockFileDataAccessor.Directory.Delete(directoryPath, recursive);
}

public override IEnumerable<DirectoryInfoBase> EnumerateDirectories()
public override IEnumerable<IDirectoryInfo> EnumerateDirectories()
{
return GetDirectories();
}

public override IEnumerable<DirectoryInfoBase> EnumerateDirectories(string searchPattern)
public override IEnumerable<IDirectoryInfo> EnumerateDirectories(string searchPattern)
{
return GetDirectories(searchPattern);
}

public override IEnumerable<DirectoryInfoBase> EnumerateDirectories(string searchPattern, SearchOption searchOption)
public override IEnumerable<IDirectoryInfo> EnumerateDirectories(string searchPattern, SearchOption searchOption)
{
return GetDirectories(searchPattern, searchOption);
}

public override IEnumerable<FileInfoBase> EnumerateFiles()
public override IEnumerable<IFileInfo> EnumerateFiles()
{
return GetFiles();
}

public override IEnumerable<FileInfoBase> EnumerateFiles(string searchPattern)
public override IEnumerable<IFileInfo> EnumerateFiles(string searchPattern)
{
return GetFiles(searchPattern);
}

public override IEnumerable<FileInfoBase> EnumerateFiles(string searchPattern, SearchOption searchOption)
public override IEnumerable<IFileInfo> EnumerateFiles(string searchPattern, SearchOption searchOption)
{
return GetFiles(searchPattern, searchOption);
}

public override IEnumerable<FileSystemInfoBase> EnumerateFileSystemInfos()
public override IEnumerable<IFileSystemInfo> EnumerateFileSystemInfos()
{
return GetFileSystemInfos();
}

public override IEnumerable<FileSystemInfoBase> EnumerateFileSystemInfos(string searchPattern)
public override IEnumerable<IFileSystemInfo> EnumerateFileSystemInfos(string searchPattern)
{
return GetFileSystemInfos(searchPattern);
}

public override IEnumerable<FileSystemInfoBase> EnumerateFileSystemInfos(string searchPattern, SearchOption searchOption)
public override IEnumerable<IFileSystemInfo> EnumerateFileSystemInfos(string searchPattern, SearchOption searchOption)
{
return GetFileSystemInfos(searchPattern, searchOption);
}
Expand All @@ -199,17 +199,17 @@ public override DirectorySecurity GetAccessControl(AccessControlSections include
return mockFileDataAccessor.Directory.GetAccessControl(directoryPath, includeSections);
}

public override DirectoryInfoBase[] GetDirectories()
public override IDirectoryInfo[] GetDirectories()
{
return ConvertStringsToDirectories(mockFileDataAccessor.Directory.GetDirectories(directoryPath));
}

public override DirectoryInfoBase[] GetDirectories(string searchPattern)
public override IDirectoryInfo[] GetDirectories(string searchPattern)
{
return ConvertStringsToDirectories(mockFileDataAccessor.Directory.GetDirectories(directoryPath, searchPattern));
}

public override DirectoryInfoBase[] GetDirectories(string searchPattern, SearchOption searchOption)
public override IDirectoryInfo[] GetDirectories(string searchPattern, SearchOption searchOption)
{
return ConvertStringsToDirectories(mockFileDataAccessor.Directory.GetDirectories(directoryPath, searchPattern, searchOption));
}
Expand All @@ -222,41 +222,41 @@ private DirectoryInfoBase[] ConvertStringsToDirectories(IEnumerable<string> path
.ToArray();
}

public override FileInfoBase[] GetFiles()
public override IFileInfo[] GetFiles()
{
return ConvertStringsToFiles(mockFileDataAccessor.Directory.GetFiles(FullName));
}

public override FileInfoBase[] GetFiles(string searchPattern)
public override IFileInfo[] GetFiles(string searchPattern)
{
return ConvertStringsToFiles(mockFileDataAccessor.Directory.GetFiles(FullName, searchPattern));
}

public override FileInfoBase[] GetFiles(string searchPattern, SearchOption searchOption)
public override IFileInfo[] GetFiles(string searchPattern, SearchOption searchOption)
{
return ConvertStringsToFiles(mockFileDataAccessor.Directory.GetFiles(FullName, searchPattern, searchOption));
}

FileInfoBase[] ConvertStringsToFiles(IEnumerable<string> paths)
IFileInfo[] ConvertStringsToFiles(IEnumerable<string> paths)
{
return paths
.Select(mockFileDataAccessor.FileInfo.FromFileName)
.ToArray();
}

public override FileSystemInfoBase[] GetFileSystemInfos()
public override IFileSystemInfo[] GetFileSystemInfos()
{
return GetFileSystemInfos("*");
}

public override FileSystemInfoBase[] GetFileSystemInfos(string searchPattern)
public override IFileSystemInfo[] GetFileSystemInfos(string searchPattern)
{
return GetFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
}

public override FileSystemInfoBase[] GetFileSystemInfos(string searchPattern, SearchOption searchOption)
public override IFileSystemInfo[] GetFileSystemInfos(string searchPattern, SearchOption searchOption)
{
return GetDirectories(searchPattern, searchOption).OfType<FileSystemInfoBase>().Concat(GetFiles(searchPattern, searchOption)).ToArray();
return GetDirectories(searchPattern, searchOption).OfType<IFileSystemInfo>().Concat(GetFiles(searchPattern, searchOption)).ToArray();
}

public override void MoveTo(string destDirName)
Expand All @@ -269,15 +269,15 @@ public override void SetAccessControl(DirectorySecurity directorySecurity)
mockFileDataAccessor.Directory.SetAccessControl(directoryPath, directorySecurity);
}

public override DirectoryInfoBase Parent
public override IDirectoryInfo Parent
{
get
{
return mockFileDataAccessor.Directory.GetParent(directoryPath);
}
}

public override DirectoryInfoBase Root
public override IDirectoryInfo Root
{
get
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public MockDirectoryInfoFactory(IMockFileDataAccessor mockFileSystem)
this.mockFileSystem = mockFileSystem;
}

public DirectoryInfoBase FromDirectoryName(string directoryName)
public IDirectoryInfo FromDirectoryName(string directoryName)
{
return new MockDirectoryInfo(mockFileSystem, directoryName);
}
Expand Down
2 changes: 1 addition & 1 deletion System.IO.Abstractions.TestingHelpers/MockDriveInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public MockDriveInfo(IMockFileDataAccessor mockFileDataAccessor, string name) :
public new bool IsReady { get; protected set; }
public override string Name { get; protected set; }

public override DirectoryInfoBase RootDirectory
public override IDirectoryInfo RootDirectory
{
get
{
Expand Down
4 changes: 2 additions & 2 deletions System.IO.Abstractions.TestingHelpers/MockDriveInfoFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public MockDriveInfoFactory(IMockFileDataAccessor mockFileSystem)
this.mockFileSystem = mockFileSystem ?? throw new ArgumentNullException(nameof(mockFileSystem));
}

public DriveInfoBase[] GetDrives()
public IDriveInfo[] GetDrives()
{
var driveLetters = new HashSet<string>(new DriveEqualityComparer(mockFileSystem));
foreach (var path in mockFileSystem.AllPaths)
Expand All @@ -38,7 +38,7 @@ public DriveInfoBase[] GetDrives()
return result.ToArray();
}

public DriveInfoBase FromDriveName(string driveName)
public IDriveInfo FromDriveName(string driveName)
{
var drive = mockFileSystem.Path.GetPathRoot(driveName);

Expand Down
Loading