2010-05-05 15 views
17

Ho una classe che ha un metodo interno e voglio prendere in giro il metodo interno. Ma non riesco a deriderlo, cioè non chiama la funzione derisoria ma chiama la funzione originale. C'è un modo per raggiungere questo obiettivo?Come deridere il metodo interno di una classe?

Modifica: In realtà io sono un novizio del Moq. Ho molte classi e metodi delle classi per testare usando il Moq. Molte classi sono interne, molte hanno metodi interni, molte hanno metodi non virtuali. E non può cambiare la firma sui metodi e sulle classi. Qualcuno può per favore fammi sapere come andare a testare questo scenario usando Moq. Oppure, per favore, suggeriscimi qualche altro framework di test che sia facile da apprendere e facile da usare.

risposta

2

Perché vuoi prendere in giro un metodo interno?

Se si riscontra la necessità di prendere in giro un metodo interno, ad esempio per evitare una dipendenza o un'interazione, è consigliabile prendere in considerazione la riprogettazione della classe.

Inversion of Control e sono alcune possibili strategie di progettazione che possono ridurre l'accoppiamento e aumentare la coesione delle classi ed eliminare la necessità di prendere in giro metodi interni.

Non credo che ci sia un percorso chiaro per deridere non pubblico con Moq.

Ma, se assolutamente necessario, è possibile utilizzare TypeMock Isolator per simulare qualsiasi cosa.

Inoltre, proprio così non si perde nel frastuono: Thomas ha collegato un buon articolo sull'utilizzo dei MS Moles gratuiti per deridere membri non pubblici.

Mocking the Unmockable: Using Microsoft Moles with Gallio

+1

Infatti, scherno metodi privati ​​tipico odore di codice. – mikek

+5

Non sono assolutamente d'accordo: se fai TDD, il fatto di prendere in giro cose interne è una cosa normale, di tutti i giorni ... –

+0

@Thomas - Capisco la tua prospettiva. Ma devi capire che la strategia classica è definita come testare un comportamento di classi, tipicamente tramite interfaccia, piuttosto che implementazione interna in quanto questo accoppia strettamente i test con l'implementazione interna e induce inerzia e rottura durante il refactoring. Devo dire che sei in minoranza con la tua opinione. nota: ho letto un po 'del tuo blog e so che sei abbastanza premuroso e TDD ti è caro, non sono d'accordo con il tuo disaccordo. ;-) –

1

Unità di test deve testare l'interfaccia di una classe. È possibile prendere in giro le dipendenze, ma i dettagli di implementazione della classe stessa (come i metodi privati) dovrebbero essere testati come parte dell'intera classe, non separatamente, e non modificati per il test (altrimenti si testerebbe un'unità diversa, quindi sarebbe davvero essere usato).

Se si ritiene necessario modificare il metodo per rendere testabile la classe, rifattorizzare la classe in modo che la parte difficile diventi una dipendenza o in altro modo sostituibile da un parametro o una sottoclasse.

+0

Che cosa succede se sviluppi il test del codice, in primo luogo, a piccoli passi? Avrai regolarmente bisogno di gestire il codice interno in un modo o nell'altro ... –

3

Non con Moq.

Ma è possibile utilizzare il framework Moles gratuito di MS per fare queste cose. Ho scritto su di esso qui: Mocking the Unmockable: Using Microsoft Moles with Gallio. (si applica non solo a Gallio, ma dà una buona impressione generale di cosa si può fare con Moles ...). L'altra alternativa sarebbe Typemock ...

HTH. Thomas

+0

+ per l'articolo sugli strumenti gratuiti –

+1

Sbagliato (almeno nel 2016). Vedi la risposta di Daryn. – mhvelplund

+0

A partire dal 2016, MS Moles è stato sostituito con MS Fakes, secondo http://wayback.archive.org/web/20160316031214/http://research.microsoft.com/en-us/projects/moles/. – clacke

0

Se è necessario testare un sacco di codice che non è possibile modificare, è consigliabile utilizzare MS Moles o TypeMock dall'inizio.

I framework di simulazione libera come Moq forniscono comunque supporto solo su interfacce e metodi virtuali. Non suona come se si andrà lontano con quella ...

Thomas

55

Si può facilmente finte metodi virtuali interni aggiungendo quanto segue al AssemblyInfo.cs:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // namespace in Moq 
[assembly: InternalsVisibleTo("YourTestClass")] 

Se il montaggio è un nome sicuro, è necessario includere la chiave pubblica per DynamicProxyGenAssembly2 (Grazie a commento di @bvgheluwe; fonte: Moq quickstart guide):

[assembly:InternalsVisibleTo("DynamicProxyGenAssembly2,PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] 

Non capisco perché la risposta accettata dice che non dovresti mai farlo. Non è quello che fai quando usi la tecnica di iniezione delle dipendenze "Estrai e Sostituisci" (metodo factory locale) delineata da Roy Osherove in Chapter 3 of The Art Of Unit Testing?

+1

Questo mi ha aiutato molto. Grazie! – Fabian

+9

Questa dovrebbe essere la risposta accettata. È tutto un altro dibattito sul fatto che prendere in giro un metodo interno sia la cosa giusta da fare, tuttavia se hai deciso che è quello che vuoi fare, questo è il modo per ottenerlo. – CraigTP

+2

Questo non funzionerà. Hai bisogno anche di una chiave pubblica. – max

22

Seleziona il metodo internal *protected* (anche virtuali ovviamente)

+2

omg, l'hai risolto. – max

+0

Funziona, ma puoi dirci perché funziona? – MrLore

+1

@MrLore funziona perché "_protected_ internal" significa che il metodo è accessibile da una sottoclasse in _any_ assembly e se lo contrassegni "virtuale" la sottoclasse mocking può fornire un'implementazione personalizzata – andreister

Problemi correlati