2012-05-23 3 views
12

Sto cercando di Setup il ritorno di una chiamata a un metodo di estensione e sto ricevendo:risultato installazione per chiamata al metodo di estensione

SetUp : System.NotSupportedException : Expression references a method that does not belong to the mocked object: m => m.Cache.GetOrStore<String>("CacheKey",() => "Foo", 900)

E sembra avere un problema con riferimento al metodo GetOrStore su l'oggetto Cache che è un metodo di estensione.

Il codice viene compilato ma il test ha esito negativo con questa eccezione.

Cosa devo fare per impostare il risultato di un metodo di estensione come questo?

+2

Hai deriso i metodi/proprietà utilizzati nel metodo di estensione? –

+0

Il metodo di estensione è un metodo statico in una classe statica. Non mi aspetto che venga effettivamente chiamato 'GetOrStore' e quindi i metodi che chiama non dovrebbero essere presi in considerazione, giusto? –

+0

'GetOrStore' chiama' Get' e 'Insert' sull'oggetto' Cache'. Il metodo 'GetOrStore' non dovrebbe essere in esecuzione, visto che è un finto ... –

risposta

19

I metodi di estensione non possono essere presi in giro come metodi di istanza perché non sono definiti sul tuo tipo di mocked. Sono definiti in altre classi statiche. Dal momento che non puoi semplicemente prendere in giro quelli, invece dovresti prendere in giro tutti i metodi/proprietà usati dal metodo di estensione.

Questo è un esempio di come i metodi di estensione accoppiano strettamente il codice ad altre classi. Qualunque cosa tu faccia, la tua classe dipende da quei metodi statici. Non puoi prenderlo in giro e provarlo da solo. Suggerisco di refactoring il codice per spostare quei metodi per le proprie classi se c'è qualche logica all'interno.

+1

Grazie per il vostro aiuto. Ho deciso di abbandonare il metodo di estensione e impiantare il mio ICache come suggerito. Tutto sembra molto più semplice ora. –

5

Moq non è in grado di simulare metodi statici, quindi non sarà in grado di prendere in giro l'estensione GetOrStore.

Invece, basta prendere in giro i metodi Get e Insert dell'oggetto Cache.

+0

Grazie a @FlorianGreinacher. L'unico problema è che non riesco a impostare 'Get' dal momento che non è virtuale. –

0

E 'possibile, anche se non bello ... Presumo che ci sia qualche oggetto cache interno nel tuo metodo di estensione, o un riferimento ad alcune cache da qualche parte. È possibile utilizzare la riflessione per sostituire l'oggetto interno per memorizzare la cache. Si ottiene qualcosa di simile all'interno del test:

IFixture fixture = new Fixture().Customize(new AutoMoqCustomization()); 

Mock<ICache> internalCache = new Mock<ICache>(); 
internalCache.Setup(i => i.Get<String>("CacheKey")).Returns("Foo"); 

var cacheExtension = typeof(CacheExtensions); 
var inst = cacheExtension.GetField("_internalCache", BindingFlags.NonPublic | BindingFlags.Static); 
inst.SetValue(cacheExtension, internalCache.Object); 

Si noti che questo codice non è testato, ma dovrebbe spiegare l'idea di base.