Au cœur de la bibliothèque se trouve IFileSystem
et FileSystem
. Au lieu d'appeler des méthodes comme File.ReadAllText
directement, utilisez IFileSystem.File.ReadAllText
. Nous avons exactement la même API, sauf que le nôtre est injectable et testable.
dotnet add package TestableIO.System.IO.Abstractions.Wrappers
Remarque: Ce package NuGet est également publié sous le nom de System.IO.Abstractions
, mais nous suggérons d'utiliser le préfixe pour indiquer clairement qu'il ne s'agit pas d'un package .NET officiel.
public class MyComponent
{
readonly IFileSystem fileSystem ;
// <summary>Create MyComponent with the given fileSystem implementation</summary>
public MyComponent ( IFileSystem fileSystem )
{
this . fileSystem = fileSystem ;
}
/// <summary>Create MyComponent</summary>
public MyComponent ( ) : this (
fileSystem : new FileSystem ( ) //use default implementation which calls System.IO
)
{
}
public void Validate ( )
{
foreach ( var textFile in fileSystem . Directory . GetFiles ( @"c:" , " *.txt " , SearchOption . TopDirectoryOnly ) )
{
var text = fileSystem . File . ReadAllText ( textFile ) ;
if ( text != " Testing is awesome. " )
throw new NotSupportedException ( " We can't go on together. It's not me, it's you. " ) ;
}
}
}
La bibliothèque est également expédiée avec une série de tests de test pour vous éviter d'avoir à se moquer de chaque appel, pour des scénarios de base. Ils ne sont pas une copie complète d'un système de fichiers réel, mais ils vous mèneront le plus.
dotnet add package TestableIO.System.IO.Abstractions.TestingHelpers
Remarque: Ce package NUGET est également publié sous le nom de System.IO.Abstractions.TestingHelpers
, mais nous suggérons d'utiliser le préfixe pour indiquer clairement qu'il ne s'agit pas d'un package .NET officiel.
[ Test ]
public void MyComponent_Validate_ShouldThrowNotSupportedExceptionIfTestingIsNotAwesome ( )
{
// Arrange
var fileSystem = new MockFileSystem ( new Dictionary < string , MockFileData >
{
{ @"c:myfile.txt" , new MockFileData ( " Testing is meh. " ) } ,
{ @"c:demojQuery.js" , new MockFileData ( " some js " ) } ,
{ @"c:demoimage.gif" , new MockFileData ( new byte [ ] { 0x12 , 0x34 , 0x56 , 0xd2 } ) }
} ) ;
var component = new MyComponent ( fileSystem ) ;
try
{
// Act
component . Validate ( ) ;
}
catch ( NotSupportedException ex )
{
// Assert
Assert . That ( ex . Message , Is . EqualTo ( " We can't go on together. It's not me, it's you. " ) ) ;
return ;
}
Assert . Fail ( " The expected exception was not thrown. " ) ;
}
Nous soutenons même la coulée des types non testables du framework .NET à nos emballages testables:
FileInfo SomeApiMethodThatReturnsFileInfo ( )
{
return new FileInfo ( " a " ) ;
}
void MyFancyMethod ( )
{
var testableFileInfo = ( FileInfoBase ) SomeApiMethodThatReturnsFileInfo ( ) ;
.. .
}
Depuis la version 4.0, les API de niveau supérieur exposent les interfaces au lieu des classes de base abstraites (celles-ci existent toujours), vous permettant de se moquer complètement du système de fichiers. Voici un petit exemple, en utilisant le MOQ:
[ 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:SomeDirectory" , " 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 ) ;
}
}
}
System.IO.Abstractions.Extensions
offre une fonctionnalité de commodité en plus des abstractions de base.
System.IO.Abstractions.Analyzers
fournit des analyseurs Roslyn pour aider à utiliser les abstractions par rapport aux méthodes statiques.
Testably.Abstractions
fournit des aides de test alternatifs et des abstractions supplémentaires.