En el núcleo de la biblioteca se encuentra IFileSystem
and FileSystem
. En lugar de llamar a métodos como File.ReadAllText
directamente, use IFileSystem.File.ReadAllText
. Tenemos exactamente la misma API, excepto que la nuestra es inyectable y comprobable.
dotnet add package TestableIO.System.IO.Abstractions.Wrappers
Nota: Este paquete Nuget también se publica como System.IO.Abstractions
pero sugerimos usar el prefijo para dejar en claro que este no es un paquete oficial de .NET.
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 biblioteca también se envía con una serie de ayudantes de prueba para evitar tener que burlarse de cada llamada, para escenarios básicos. No son una copia completa de un sistema de archivos de la vida real, pero lo llevarán la mayor parte del camino.
dotnet add package TestableIO.System.IO.Abstractions.TestingHelpers
Nota: Este paquete Nuget también se publica como System.IO.Abstractions.TestingHelpers
, pero sugerimos usar el prefijo para dejar en claro que este no es un paquete oficial de .NET.
[ 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. " ) ;
}
Incluso admitimos el lanzamiento de los tipos no más probables del marco de .NET a nuestros envoltorios comprobables:
FileInfo SomeApiMethodThatReturnsFileInfo ( )
{
return new FileInfo ( " a " ) ;
}
void MyFancyMethod ( )
{
var testableFileInfo = ( FileInfoBase ) SomeApiMethodThatReturnsFileInfo ( ) ;
.. .
}
Desde la versión 4.0, las API de nivel superior exponen las interfaces en lugar de las clases base abstractas (aunque todavía existen), lo que le permite burlarse por completo del sistema de archivos. Aquí hay un pequeño ejemplo, usando 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
proporciona funcionalidad de conveniencia además de las abstracciones centrales.
System.IO.Abstractions.Analyzers
Analyzers proporciona analizadores de Roslyn para ayudar a usar abstracciones sobre métodos estáticos.
Testably.Abstractions
proporcionan ayudantes de prueba alternativos y abstracciones adicionales.