2012-03-02 8 views
10

Actualmente estoy tratando de aprender la prueba de la unidad adecuada. Así que ahora estoy tratando de escribir pruebas unitarias para una clase que debe mapear datos de un archivo XML a los objetos adecuados. Por supuesto, toda la funcionalidad de la clase depende de la existencia del archivo XML correspondiente. El archivo XML se carga en el constructor de la clase.Cómo probar la unidad de una clase que necesita un archivo específico para estar presente

Estoy usando C# con NUnit. Hasta ahora tengo dos pruebas:

[Test] 
public void ShouldAllowInstanceToBeCreatedWhenXMLFileIsPresent() 
{ 
    if (File.Exists(SettingsReader.XML_SETTINGS_PATH)) 
    { 
     SettingsReader settingsReader = new SettingsReader(); 
     Assert.AreNotEqual(null, settingsReader); 
    } 
} 

[Test] 
[ExpectedException("Telekanzlei.Clientmanager.XMLDataLayer.XMLFileNotFoundException")] 
public void ShouldThrowExceptionWhenXMLFileIsNotPresent() 
{ 
    if (!File.Exists(SettingsReader.XML_SETTINGS_PATH)) 
    { 
     SettingsReader settingsReader = new SettingsReader(); 
    } 
     else 
      throw new XMLFileNotFoundException(); 
    } 

No estoy seguro de si la comprobación de la existencia del archivo en el examen es una forma adecuada para ir, por lo que cualquier sugerencia sobre los que la prueba también son bienvenidos. Pero mi pregunta es cómo proceder con las siguientes pruebas. Obviamente, todas las siguientes pruebas van a fallar, si el archivo XML no está presente.

Entonces, ¿supongo que el archivo XML está presente, teniendo en cuenta que una prueba errónea podría significar que no lo está? Eso no me parece correcto.

¿Existe un patrón general para solucionar un problema como este?

Thx por la ayuda

edición: volvió a escribir la segunda prueba, ya que estaba fallando si el archivo estaba realmente presente ...

Edit2: Que es ayudar a decirle, lo que la realidad SettingsReader hace. Hasta ahora se ve así:

public class SettingsReader 
{ 
    public static readonly string XML_SETTINGS_PATH = "C:\\Telekanzlei\\Clientmanager_2.0\\Settings.xml"; 

    public XElement RootXElement { get; private set; } 

    public SettingsReader() 
    { 
     if (!File.Exists(XML_SETTINGS_PATH)) 
      throw new XMLFileNotFoundException(); 
     using (var fs = File.OpenRead(XML_SETTINGS_PATH)) 
     { 
      RootXElement = XElement.Load(fs); 
     } 
    } 


} 

no estoy seguro, pero creo que un StreamReader no sería el camino a seguir aquí, ¿verdad?

+3

¿Está el editor de configuración diseñado para usar la inyección de dependencia? Suena como un buen caso para DI y burla. –

+1

MSTest tiene [DeploymentItem] para esto. ¿Tal vez NUnit tiene algo así? –

Respuesta

14

El problema no es con las pruebas de su unidad, sino con el diseño de la clase. Sugeriría refactorizar la clase para que no abra el archivo, sino que funcione en una transmisión. Entonces, las pruebas de su unidad podrían simplemente reemplazar una secuencia de archivos por una secuencia de memoria: ¡simples! :)

public class SettingsReader() 
{ 
    public SettingsReader(System.IO.StreamReader reader) 
    { 
     // read contents of stream... 
    } 
} 

// In production code: 
new SettingsReader(new StreamReader(File.Open("settings.xml"))); 

// In unit test: 
new SettingsReader(new StringReader("<settings>dummy settings</settings>")); 

Recuerde, abrir un archivo y analizar los datos de configuración son dos preocupaciones muy diferentes.

+0

Me acabo de dar cuenta de que el método XElement.Load toma una secuencia como parámetro. Todavía no estoy familiarizado con .NET. Pero su sugerencia parece un buen enfoque. ¿Entonces voy a dividir eso en digamos una clase de SettingsStreamProvider y una clase de SettingsParser y usar la inyección de dependencia para el analizador? – Tobi

+0

¿Qué valor tendría una clase de proveedor de flujo de configuración solo en una secuencia simple? Creo que sería una abstracción sin sentido - KISS :) – MattDavey

+0

Punto tomado ^^ La cosa es thoughm Estoy usando el SettingsReader en múltiples ocasiones en mi proyecto, pero siempre con el mismo archivo XML. No me gustaría mucho crear una nueva secuencia "manualmente" cada vez que la utilizo. Es por eso que quería manejar la apertura de la secuencia en la clase SettingsReader en primer lugar ... – Tobi

5

Si debe sugerir que use SetUp método para copiar o verificar que el archivo exista. Sugiero asegurarme de que el archivo esté presente agregándolo al proyecto de prueba y marcándolo como "copiar siempre" una vez que funciona, no hay necesidad de volver a verificarlo.
Si tiene muchas pruebas que requieren archivos externos, quizás debería usar MsTest; tiene un atributo llamado DeploymentItem que asegura que el archivo se copie en la misma ubicación que la prueba.

3

Considere reescribir el código para que las dependencias puedan pasarse o de alguna otra manera anularse para el código que desea probar unitario.

I.e. pase algo como la instancia "IMySettingsFileProvider" al constructor de SettingsReader donde IMySettingsFileProvider.SettingsXml devuelve alguna secuencia de configuración. De esta forma, puede simular la interfaz IMySettingsFileProvider para la prueba en lugar de requerir que el archivo esté presente en el disco.

+1

¿No sería eso un "exceso"? El archivo XML solo lo usa esta clase. ¿Crear una clase Interface + solo para cargar el archivo? – Tobi

+1

De acuerdo. No entiendo por qué las personas agregan tanta complejidad a la burla simplemente porque es la forma "pura" de hacerlo. Es mejor aprovechar el código que creó el archivo para crearlo/copiarlo a una ubicación temporal, usarlo y luego eliminarlo. – tsells

+0

Sí, podría ser. Por eso intenté escribir "considerar ..." - si funciona para su caso que hacer eso, si no - haga otra cosa (que ya fue sugerida como respuesta anterior). –

1

Una opción es poner esto en la parte superior del accesorio de prueba. Entonces las pruebas solo serán válidas cuando el archivo exista.

[SetUp] 
public void Setup() 
{ 
    Assume.That(File.Exists(SettingsReader.XML_SETTINGS_PATH)); 
} 
Cuestiones relacionadas