2012-01-07 6 views
6

Quiero crear código de unidad de prueba que burla las llamadas a las clases .Net System.IO, así que realmente puedo probar la unidad en lugar de depender del sistema de archivos. Estoy usando las clases SystemWrapper para envolver las clases BCL.¿Cómo crear código comprobable usando clases de IO de .Net?

Estoy tratando de obtener un ejemplo simple de trabajo para ver si existe un archivo.

El problema que tengo es que inyectar la dependencia en la clase no funciona porque la instanciación de la dependencia (a través de StructureMap) requiere saber qué parámetro constructor pasar, que no estará disponible en ese momento, también hay sin constructor por defecto

código de ejemplo:

// don't want to create dependency here like so 
//IFileInfoWrap fileInfoWrap = new FileInfoWrap(filename); 

// using service locator (anti-pattern?!) since it can't be 
// injected in this class 
var fileInfoWrap = ObjectFactory.GetInstance<IFileInfoWrap>(
    new ExplicitArguments(new Dictionary<string, object> 
    { 
     {"fileName", filename} 
    })); 

Console.WriteLine("File exists? {0}", fileInfoWrap.Exists); 

Lo que no me gusta es que la dependencia no se inyecta, ObjectFactory no debería estar aquí (pero no veo otra manera de crear este). ExplicitArguments lo hace desordenado y el argumento-nombre es una cadena de magia.

para mí para conseguir que esto funcione clase StructureMap config necesita saber explict qué constructor quiero usar (acabo de empezar con StructureMap por lo que este podría no ser el camino correcto para configurarlo):

ObjectFactory.Initialize(x => 
{ 
    x.Scan(scan => 
    { 
     scan.AssembliesFromPath("."); 
     scan.RegisterConcreteTypesAgainstTheFirstInterface(); 
     scan.WithDefaultConventions(); 
    }); 

    // use the correct constructor (string instead of FileInfo) 
    x.SelectConstructor(() => new FileInfoWrap(null as string)); 

    // setting the value of the constructor 
    x.For<IFileInfoWrap>() 
     .Use<FileInfoWrap>() 
     .Ctor<string>("fileName") 
     .Is(@"."); 
}); 

¿Alguien encontró una mejor solución para crear un código comprobable contra las clases System.IO? Sé que parte del problema está en el diseño de las clases System.IO.

+3

SystemWrapper contiene abstracciones sobre todo muy permeables. Sería mucho más simple y fácil modelar IO contra Streams, TextWriter, TextReader, etc. Estas clases ya son abstractas, eliminando por completo la necesidad de SystemWrapper. –

+0

Otro voto para las transmisiones –

+0

Mis conclusiones con SystemWrapper son que parece ser un buen contenedor con interfaces, sin embargo, sigue siendo un callejón sin salida debido a la forma en que funcionan las clases originales. Por ejemplo, devolver una matriz de objetos FileInfo no se puede burlar correctamente. Rodando mi propio envoltorio más simplificado que no tiene que imitar a las clases existentes, mientras que más trabajo me lleva a una solución viable en mi humilde opinión. –

Respuesta

5

Un enfoque que he utilizado con mucho éxito es rodar mis propios tipos de proxy para los tipos encontrados en System.IO y otras partes de la FCL. P.ej. Quiero tomar una dependencia en System.IO.File. Creo una biblioteca llamada System.IO.Proxies y agrego un tipo concreto File y una interfaz IFile. La interfaz IFile expone miembros equivalentes a todos los que necesito de System.IO.File y el tipo concreto implementa esos miembros haciendo nada más que enviar llamadas a System.IO.File. System.IO.Proxies está excluido de las pruebas unitarias y la cobertura del código. En mi ensamblado consumidor, tomo una dependencia solo en System.IO.Proxies y, específicamente, solo tomo una dependencia en IFile. De esta manera puedo burlarme de esta dependencia fácilmente y obtener una cobertura de código del 100% para mi ensamblaje consumidor.

(Tenga en cuenta que esta es una versión adaptada de mi more general answer a una pregunta anterior.)

+0

Sí, esa es la forma en que terminé también. Se podría delegar la llamada a, p. System.IO.FileInfo a una clase separada. Rolar su propio proxy requiere la creación de un proxy para cada clase, lo que podría ser bastante trabajo, por supuesto, puede crecer junto con la funcionalidad necesaria de la clase BCL. También cuando se devuelven otros tipos (FileInfo), todos los atributos necesarios deben crearse en el proxy (Nombre, Nombre completo, Longitud). Uno pensaría que este problema estaría 'resuelto', ya que evita el proxy para todos. –

+0

Usó el mismo enfoque con bastante éxito. Por lo general, no necesita todos los métodos/propiedades/eventos de una clase como _File_. Y para el puñado que necesita es realmente fácil escribir tales envoltorios. –

Cuestiones relacionadas