2009-08-05 12 views
14

Quiero cargar un archivo XML externo en una prueba unitaria para probar algún código de procesamiento en ese XML. ¿Cómo obtengo la ruta del archivo?Cómo utilizar MapPath en una prueba unitaria en C#

lo general, en una aplicación web que haría:

XDocument.Load(Server.MapPath("/myFile.xml")); 

Pero, obviamente, en mi unidad de prueba no tengo ninguna referencia al servidor o HttpContext así que ¿cómo puedo asignar un camino para que yo no tengo que especifique el camino completo?

ACTUALIZACIÓN:

sólo quiero dejar claro que el código realidad estoy probando es para una clase de analizador XML, algo así como:

public static class CustomerXmlParser { 
    public static Customer ParseXml(XDocument xdoc) { 
    //... 
    } 
} 

Así que para probar esto necesito para analizar un XDocument válido El método que se prueba no accede al sistema de archivos en sí. Pude crear el XDocument desde una Cadena directamente en el código de prueba, pero pensé que sería más fácil simplemente cargarlo desde un archivo.

Respuesta

24

Otra idea sería utilizar la dependencia injecti en.

public interface IPathMapper { 
string MapPath(string relativePath); 
} 

y luego usar simplemente 2 implementaciones

public class ServerPathMapper : IPathMapper { 
    public string MapPath(string relativePath){ 
      return HttpContext.Current.Server.MapPath(relativePath); 
    } 
} 

Y entonces también necesita su ejecución simulada

public class DummyPathMapper : IPathMapper { 
    public string MapPath(string relativePath){ 
     return "C:/Basedir/" + relativePath; 
    } 
} 

Y entonces todas las funciones que necesita para trazar el camino de simplemente necesita tener acceso a una instancia de IPathMapper: en su aplicación web necesita ser ServerPathMapper y en su unidad prueba DummyPathMapper - basic DI (Dependency Injection).

+0

¿Cuál es el beneficio de la interfaz aquí? En su lugar, ¿podemos simplemente crear 2 archivos de clase y llamarlos en consecuencia 1 desde una aplicación real y 1 desde el punto final de la prueba? ¿Puede alguien explicar el beneficio de esta interfaz aquí? –

+0

Al usar clases, debe decidir que una clase herede de la otra para que el sistema de tipos sea feliz. Tener su implementación de prueba heredando la real, o al revés, no es realmente una solución ideal. Al hacerlo de esta manera, no es necesario que sus implementaciones real y de prueba se conozcan entre sí, solo que tienen una interfaz común que necesitan satisfacer. – kastermester

5

Personalmente, sería muy cauteloso al tener un código que dependa de un almacén de recursos , ya sea un sistema de archivos o una base de datos; está introduciendo una dependencia en la prueba unitaria que probablemente lleve a los negativos falsos, es decir, las pruebas no se producen debido a su código de prueba específico, sino porque el archivo no está allí o el servidor no está disponible, etc.
Consulte esta link para IMO una buena definición de lo que es una prueba unitaria y más importante no es

La prueba de su unidad debe probar una funcionalidad atómica bien definida que no pruebe si un archivo puede cargarse. Una solución es "burlarse" de la carga de archivos. Sin embargo, hay varios enfoques para esto. Personalmente solo me burlaría de la interfaz del sistema de archivos que está utilizando y no intentaré hacer burla alguna del sistema de archivos. here's una buena publicación y here's una buena discusión para el sistema de archivos burlarse

Espero que ayude

+0

Para que quede claro, no estoy probando si el XML se puede cargar o comprobar el contenido del archivo, estoy probando una pieza de código que requiere un XDocument para ser analizado. El archivo se ubica con las pruebas si no se carga, entonces la prueba mostrará un error y no un falso negativo. Me doy cuenta de que esto no es ideal, pero no sé de ninguna otra manera. He actualizado mi pregunta. –

+0

Sin duda, ese es el punto, ¿no es así? Su código está probando su analizador, por lo tanto, de dónde provienen los datos XML es irrelevante y no debería fallar porque el archivo no existe. Personalmente, me gustaría ir con la opción de cadena o podría tenerlo como un recurso incrustado – zebrabox

3

lo general, para las pruebas unitarias que añadir los archivos XML como recursos incrustados en el proyecto y cargarlos utilizando un método como este:

public static string LoadResource(string name) 
{ 
    Type thisType = MethodBase.GetCurrentMethod().DeclaringType; 
    string fullName = thisType.Namespace + "." + name + ".xml"; 

    using (Stream stream = thisType.Module.Assembly.GetManifestResourceStream(fullName)) 
    { 
     if(stream==null) 
     { 
     throw new ArgumentException("Resource "+name+" not found."); 
     } 

     StreamReader sr = new StreamReader(stream); 
     return sr.ReadToEnd(); 
    } 
} 
2

Editar: Estoy empezando desde cero porque supongo que interpreté su pregunta al principio.

La mejor manera de cargar un archivo XML en su unidad de prueba para inyectarlo luego a algunas de sus clases es usar el atributo DeploymentItem en las pruebas de unidades MS.

Esto se verá como la siguiente:

[TestMethod] 
[DeploymentItem(@"DataXmlFiles\MyTestFile.xml", "DataFiles")] 
public void LoadXMLFileTest() 
{ 
    //instead of "object" use your returning type (i.e. string, XDocument or whatever) 
    //LoadXmlFile could be a method in the unit test that actually loads an XML file from the File system 
    object myLoadedFile = LoadXmlFile(Path.Combine(TestContext.TestDeploymentDir, "DataFiles\\MyTestFile.xml")); 

    //do some unit test assertions to verify the outcome 
} 

no he probado el código ahora en un depurador, pero debería funcionar.

Editar: Por cierto, cuando se utiliza DeploymentItem consideran este post here.

1

Clases:

internal class FakeHttpContext : HttpContextBase 
{ 
    public override HttpRequestBase Request { get { return new FakeHttpRequest(); } } 
} 

internal class FakeHttpRequest : HttpRequestBase 
{ 
    public override string MapPath(string virtualPath) 
    { 
     return /* your mock */ 
    } 
} 

Uso:

[TestMethod] 
public void TestMethod() 
{ 
    var context = new FakeHttpContext(); 
    string pathToFile = context.Request.MapPath("~/static/all.js"); 
} 
Cuestiones relacionadas