2011-03-27 5 views
5

Tengo una clase que toma una instancia de MethodInfo y extrae algo de información de ella, pero me gustaría simular esta clase. Por el momento es difícil porque requiere un MethodInfo, por lo que mi plan era crear un contenedor para la clase MethodInfo e implementar una interfaz en él. Por ejemplo:Simulacros de clases .NET que utilizan clases contenedoras

public interface IMethodInfo 
{ 
    string Name { get; } 
} 

public class MethodInfoProxy : IMethodInfo 
{ 
    private readonly MethodInfo _method; 
    public MethodInfoProxy(MethodInfo method) 
    { 
     _method = method; 
    } 

    public string Name { get { return _method.Name; } } 
} 

public class MyClass 
{ 
    public MyClass(IMethodInfo method) 
    { 
     ... 
    } 
} 

Otro ejemplo sería el método File.Exists. El pensamiento sería crear un IFile.Exists y ponerlo en una clase FileProxy que simplemente delegaría a File.Exists.

Como soy nuevo en el mundo entero de pruebas de unidades, me gustaría saber si esto se consideraría un buen enfoque para tomar.

+1

Realmente no veo por qué el hecho de que se necesita un objeto MethodInfo plantea un problema al burlarse de la clase? – wendazhou

+0

Acabo de notar que MethodInfo usa la interfaz _MethodInfo que podría usar. Pero, ¿y si quisiera burlarme de Directory.Exists o File.Exists? Si creé una clase contenedora para cada clase/método/propiedad que necesito, entonces supongo que sería más fácil cuando la unidad pruebe mis clases. – MotoSV

Respuesta

3

Usted tiene dos opciones:

  1. utilizar un marco de burla como Microsoft Moles o TypeMock Isolator que pueden burlarse de clases estáticas y sellados. Esto es genial porque no termina cambiando su código solo para aislar el código bajo prueba de sus dependencias.
  2. Definición de interfaces para comportamientos que desea simular y, a continuación, creación de una implementación predeterminada que envuelve una llamada estática u otra API difícil de probar. Este es el enfoque que ha sugerido y uno que he usado mucho. La clave, al definir estas interfaces es pasar la implementación real/simulada de la interfaz en la clase de prueba a través de alguna forma de dependency injection, generalmente inyección de constructor.Algunas personas cometen el error de construir el objeto dentro de la clase que se prueba y eso hace que sea imposible probarlo. Una buena regla general es que cuando ve objetos que se construyen en su código comercial, entonces ese es un olor a código, no siempre es algo malo, pero definitivamente algo que ver con sospecha. Hay un gran video sobre esto: The Clean Code Talks - "Global State and Singletons".

Hay una pequeña guerra religiosa entre los que piensan que las pruebas no deberían cambiar el código y las que creen que deberían hacerlo. La inyección de dependencia, que es esencial si se va a burlar mediante la creación de interfaces, conduce a un código con alta cohesión y acoplamiento flexible y una API intuitiva. Pero el otro enfoque no está excluido de estos beneficios, simplemente no es tan automático.

+0

He echado un vistazo a Moles y creo que podría ser útil. Para el problema MethodInfo, podría usar la interfaz _MethodInfo, pero para cosas como File.Exists ahora estoy debatiendo si usar Moles o crear una interfaz y clase IFileSystem. El enfoque de interfaz ayuda con el desacoplamiento, pero esto podría ser demasiado trabajo para un beneficio demasiado pequeño (en este momento de todos modos). Tendré que pensar en esto. – MotoSV

+0

Una de las desventajas del enfoque de interfaz es que terminas con muchas interfaces. Peor aún, el estudio visual "Ir a declaración" y otros asistentes de navegación van a la interfaz y no al código de implementación, por lo que analizar el nuevo código puede verse un poco afectado. Moles es genial, pero tiende a fomentar el uso de código estático, que es la pesadilla de las pruebas automatizadas. – sheikhjabootie

0

Una clase falsa (o una clase falsa) sería una clase que usted hace para satisfacer las dependencias y hacer que su prueba sea más determinista al descartar problemas en sus dependencias.

public interface IMethodInfo 
{ 
    string Name { get; } 
} 

Su clase simulada:

FakeMethodInfo : IMethodInfo 
{ 
string Name {get {return "FakeMethod";}} 
} 

Ahora, en su prueba de unidad, pasar la clase FakeMethodInfo donde se necesita un IMethodInfo.

Todo el propósito es que usted sabe FakeMethodInfo simplemente devuelve una cadena por lo que si algo falla, es no es el problema.


No sé qué contexto tiene MethodInfo en su programa. Un mejor ejemplo sería

interface IUser 
{ 
string UserName {get;} 
} 

Si se implementara en una clase, obtendría el nombre de usuario real de una base de datos.

Ahora, si hace una falsa, y la pasa, simula un usuario conectado sin un usuario real, y descarta que cualquier problema tenga que ver con `IUser.

Consulte esta gran respuesta que publiqué sobre por qué utilizaría la burla. Y un ejemplo con Moq .:

Difference between Dependency Injection and Mocking framework (Ninject vs RhinoMock or Moq)

1

Recomiendo tratar de sacar las dependencias de la clase, en lugar de proporcionar un MethodInfo (o un proxy), solo suministre el Name.

Cuando eso no es práctico, puede escribir clases de proxy que utilizan una interfaz de adaptador (como ha sugerido) o utilizar una herramienta de magia negra como TypeMock o Moles (es broma sobre la parte de magia negra: I simplemente no tengo ninguna experiencia con ellos).

Si va a utilizar el enfoque de proxy, asegúrese de echar un vistazo a la biblioteca SystemWrapper, que ya maneja unas veinte clases del .NET framwork.

Cuestiones relacionadas