2010-02-19 16 views
102

ho un'interfaccia preesistente ...beffardo Metodi di estensione con Moq

public interface ISomeInterface 
{ 
    void SomeMethod(); 
} 

e ho esteso questo intreface utilizzando un mixin ...

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

ho un i thats classe di chiamare questo che voglio provare ...

public class Caller 
{ 
    private readonly ISomeInterface someInterface; 

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

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

e un test in cui mi piacerebbe prendere in giro l'interfaccia e verificare la chiamata al metodo di estensione ...

[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(); 
    } 

eseguire questo test tuttavia genera un'eccezione ...

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

La mia domanda è: esiste un bel modo per deridere la chiamata mixin?

+2

Nella mia esperienza, i termini mixin e metodi di estensione sono cose separate.Userò quest'ultimo in questo caso per evitare confusione: P –

+2

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

risposta

18

Non è possibile "simulare" direttamente il metodo statico (quindi il metodo di estensione) con la struttura di simulazione. Puoi provare Moles (http://research.microsoft.com/en-us/projects/pex/downloads.aspx), uno strumento gratuito di Microsoft che implementa un approccio diverso. Ecco la descrizione dello strumento:

Moles è un framework leggero per stub di prova e deviazioni in .NET che si basa sulla delegati.

Le mole possono essere utilizzate per deviare qualsiasi metodo .NET, inclusi metodi non virtuali/statici in tipi sigillati.

È possibile utilizzare Moles con qualsiasi framework di testing (è indipendente a tale proposito).

+2

Oltre a Moles, ci sono altri framework di simulazione (non liberi) che utilizzano l'API di profiler .NET per simulare oggetti e quindi possono sostituire qualsiasi chiamata. I due che conosco sono [Telerik's JustMock] (http://www.telerik.com/products/mocking.aspx) e [TypeMock Isolator] (http://www.typemock.com/typemock-isolator-product3). –

+3

Moles in teoria è buono, ma ho trovato tre problemi quando l'ho provato e questo mi ha impedito di usarlo ... 1) Non funziona nel runner NUnit di Resharper 2) È necessario creare manualmente un gruppo di talpa per ogni assemblato stubbato 3) È necessario ricreare manualmente un gruppo di talpe ogni volta che un metodo di prova viene modificato. –

10

Ho utilizzato un wrapper per ovviare a questo problema. Crea un oggetto wrapper e passa il tuo metodo mocked.

Vedere Mocking Static Methods for Unit Testing di Paul Irwin, ha alcuni esempi.

+0

Mi piace questa risposta perché quello che sta dicendo (senza dirlo direttamente) è necessario modificare il codice per renderlo testabile. È così che funziona. Capire che nella progettazione di microchip/IC/ASIC, questi chip devono non solo essere progettati per funzionare, ma progettati anche per essere testabili, perché se non è possibile testare un microchip, è inutile - non si può garantire che lo farà lavoro. Lo stesso vale per il software. Se non lo hai costruito per essere testabile, è ... inutile. Costruirlo per essere testabile, che in alcuni casi significa riscrivere il codice (e utilizzare i wrapper), e quindi costruire i test automatici che lo testano. –

1

Mi piace utilizzare l'involucro (modello adattatore) quando sto avvolgendo l'oggetto stesso. Non sono sicuro di usarlo per avvolgere un metodo di estensione, che non fa parte dell'oggetto.

Uso una proprietà Lazy Injectable interna di entrambi i tipi Action, Func, Predicate o delegate e consente di iniettare (swapping out) il metodo durante un test unitario.

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; 

Quindi si chiama Func invece del metodo effettivo.

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

Per un esempio più completo, controlla http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/

+0

Questo è buono, ma i lettori dovrebbero essere consapevoli che _DoWorkMethod è un nuovo campo della classe che ogni istanza della classe ora deve allocare un altro campo. È raro che ciò sia importante, ma a volte dipende dal numero di istanze che stai assegnando in qualsiasi momento. È possibile aggirare questo problema rendendo _DoWorkMethod statico. Lo svantaggio è che se si eseguono contemporaneamente test unitari, vengono completati due test di unità diversi che possono modificare lo stesso valore statico. – zumalifeguard

3

ho scoperto che ho dovuto scoprire l'interno del metodo di estensione che stavo cercando di deridere l'input per e finto che cosa stava succedendo all'interno del estensione.

Ho visto è come le estensioni sono statici, che è come mettere il codice direttamente nel metodo, quindi è necessario prendere in giro ciò che accade all'interno dell'estensione piuttosto che l'estensione stessa.

Problemi correlati