2010-02-19 21 views
102

que tienen una interfaz preexistente ...burlando de métodos de extensión con Moq

public interface ISomeInterface 
{ 
    void SomeMethod(); 
} 

y he ampliado esta intreface utilizando un mixin ...

public static class SomeInterfaceExtensions 
{ 
    public static void AnotherMethod(this ISomeInterface someInterface) 
    { 
     // Implementation here 
    } 
} 

que eso es tener una clase de llamar a este que quiero probar ...

public class Caller 
{ 
    private readonly ISomeInterface someInterface; 

    public Caller(ISomeInterface someInterface) 
    { 
     this.someInterface = someInterface; 
    } 

    public void Main() 
    { 
     someInterface.AnotherMethod(); 
    } 
} 

y una prueba en la que me gustaría burlarse de la interfaz y verificar la llamada al método de extensión ...

[Test] 
    public void Main_BasicCall_CallsAnotherMethod() 
    { 
     // Arrange 
     var someInterfaceMock = new Mock<ISomeInterface>(); 
     someInterfaceMock.Setup(x => x.AnotherMethod()).Verifiable(); 

     var caller = new Caller(someInterfaceMock.Object); 

     // Act 
     caller.Main(); 

     // Assert 
     someInterfaceMock.Verify(); 
    } 

Al ejecutar esta prueba, sin embargo genera una excepción ...

System.ArgumentException: Invalid setup on a non-member method: 
x => x.AnotherMethod() 

Mi pregunta es, ¿hay una buena manera de burlar a cabo la llamada mixin?

+2

En mi experiencia, los términos mixin y métodos de extensión son cosas separadas.Utilizaría este último en esta instancia para evitar confusiones: P –

+2

Duplicado de: http://stackoverflow.com/questions/562129/how-do-i-use-moq-to-mock-an-extension-method. – Oliver

Respuesta

18

No se puede "directamente" método estático mock (de ahí método de extensión) con burlarse marco. Puede probar Moles (http://research.microsoft.com/en-us/projects/pex/downloads.aspx), una herramienta gratuita de Microsoft que implementa un enfoque diferente. Aquí está la descripción de la herramienta:

Moles es un marco ligero para talones de prueba y desvíos en .NET que se basa en los delegados.

Moles se puede utilizar para desviar cualquier método NET, incluyendo métodos no virtuales/estáticas en tipos sellados.

Puede usar Moles con cualquier marco de prueba (es independiente de eso).

+2

Además de Moles, existen otros marcos de burla (no libres) que usan la API profiler de .NET para simular objetos y así pueden reemplazar cualquier llamada. Los dos que conozco son [Telerik's JustMock] (http://www.telerik.com/products/mocking.aspx) y [TypeMock Isolator] (http://www.typemock.com/typemock-isolator-product3). –

+3

Los lunares en teoría son buenos, pero encontré tres problemas cuando lo probé que me impidieron usarlo ... 1) No se ejecuta en el corredor de NUnit de Resharper 2) Debe crear manualmente un conjunto de mol para cada ensamblaje anulado 3) Necesitas recrear manualmente un conjunto topo cada vez que cambia un método tropezado. –

10

he utilizado una envoltura de solucionar este problema. Crea un objeto envoltorio y pasa tu método burlado.

Ver Mocking Static Methods for Unit Testing por Paul Irwin, tiene buenos ejemplos.

+0

Me gusta esta respuesta porque lo que está diciendo (sin decirlo directamente) es que necesita modificar su código para que sea comprobable. Así es como funciona. Comprenda que en el diseño de microchip/IC/ASIC, esos chips no solo deben diseñarse para funcionar, sino que deben diseñarse aún más para poder ser comprobados, ya que si no puede probar un microchip, es inútil; no puede garantizar que lo hará. trabajo. Lo mismo ocurre con el software. Si no lo ha construido para que sea comprobable, es ... inútil. Constrúyalo para que sea comprobable, lo que en algunos casos significa reescribir el código (y usar wrappers) y luego crear las pruebas automatizadas que lo prueban. –

1

me gusta usar la envoltura (adapter) cuando estoy envolviendo el objeto en sí. No estoy seguro de que use eso para envolver un método de extensión, que no es parte del objeto.

Uso una propiedad Inyectable Lazy interna de cualquier tipo Acción, Func, Predicado o delegar y permitir la inyección (intercambio) del método durante una prueba unitaria.

internal Func<IMyObject, string, object> DoWorkMethod 
    { 
     [ExcludeFromCodeCoverage] 
     get { return _DoWorkMethod ?? (_DoWorkMethod = (obj, val) => { return obj.DoWork(val); }); } 
     set { _DoWorkMethod = value; } 
    } private Func<IMyObject, string, object> _DoWorkMethod; 

Luego llama al Func en lugar del método real.

public object SomeFunction() 
    { 
     var val = "doesn't matter for this example"; 
     return DoWorkMethod.Invoke(MyObjectProperty, val); 
    } 

Para un ejemplo más completo, echa un vistazo a http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/

+0

Esto es bueno, pero los lectores deben tener en cuenta que _DoWorkMethod es un nuevo campo de la clase que cada instancia de la clase ahora tiene que asignar un campo más. Es raro que esto importe, pero a veces depende del número de instancias que está asignando en un momento dado. Puede solucionar este problema haciendo que _DoWorkMethod estético. La desventaja de esto es que si tiene pruebas unitarias que se ejecutan simultáneamente, se completarán dos pruebas unitarias diferentes que pueden modificar el mismo valor estático. – zumalifeguard

3

me di cuenta que tenía que descubrir el interior del método de extensión que estaba tratando de burlarse de la entrada para, y se burlan de lo que estaba pasando dentro de la extensión.

yo veía es como extensiones son estáticas, que es como poner el código directamente en su método, por lo que necesita para burlarse de lo que sucede dentro de la extensión en lugar de la propia extensión.

Cuestiones relacionadas