MEF e unità di test con NUnit
-
27-09-2019 - |
Domanda
Qualche settimana fa mi sono buttata sul (ComponentModel) carrozzone MEF, e ora sto usando per un sacco di miei plugin e le librerie anche condivise. Nel complesso, è stato grande a parte i frequenti errori da parte mia, che si traducono in sessioni frustranti debug.
In ogni caso, la mia app è stato in esecuzione grande, ma le mie modifiche al codice MEF-correlata hanno causato il mio automatizzato costruisce a fallire. La maggior parte dei miei test di unità sono insufficienti, semplicemente perché i moduli stavo testando erano dipende da altri moduli che dovevano essere caricati dal MEF. Ho lavorato intorno a queste situazioni bypassando MEF e istanziare direttamente quegli oggetti.
In altre parole, via MEF vorrei avere qualcosa di simile
[Import]
public ICandyInterface ci { get; set; }
e
[Export(typeof(ICandyInterface))]
public class MyCandy : ICandyInterface
{
[ImportingConstructor]
public MyCandy( [Import("name_param")] string name) {}
...
}
Ma nel mio test di unità, vorrei solo usare
CandyInterface MyCandy = new CandyInterface( "Godiva");
In aggiunta, il CandyInterface richiede una connessione ad un database, che ho lavorato in giro da solo l'aggiunta di un database di test alla mia cartella di test di unità, e non ho l'uso NUnit che, per tutti i test.
Ok, quindi qui sono le mie domande riguardo a questa situazione:
- E 'un brutto modo di fare le cose?
- Consiglieresti a comporre le parti a [SETUP]
- non ho ancora imparato a usare prende in giro in unit testing - è questo un buon esempio di un caso in cui potrei voler deridere la connessione al database sottostante (in qualche modo) per dati fittizi appena di ritorno e non realmente bisogno di un database ?
- Se hai incontrato qualcosa di simile prima, si può offrire la vostra esperienza e il modo in cui hai risolto il tuo problema? (O dovrebbe andare questo nella comunità wiki?)
Soluzione
Sembra che si è sulla strada giusta. Un test di unità dovrebbe provare un Unità , ed è quello che si fa quando si crea direttamente le istanze. Se si lascia MEF comporre le istanze per voi, avrebbero tendere test integrazione . Non che ci sia qualcosa di sbagliato con i test di integrazione, ma unit test tendono ad essere più gestibile, perché si prova ogni unità in isolamento.
Non è necessario un contenitore per cablare casi in unit test .
Io in genere raccomandare contro comporre Infissi durante la configurazione, in quanto porta alla generale Fixture contro -pattern.
E 'best practice per sostituire le dipendenze con test Doppio . irride dinamica è uno dei più versatili modi di fare questo, quindi sicuramente qualcosa che si dovrebbe imparare.
Altri suggerimenti
Sono d'accordo che la creazione delle DOC manualmente è molto meglio che usare contenitore composizione MEF per soddisfare le importazioni, ma per quanto riguarda la nota 'compositing infissi in porta di configurazione per il dispositivo generale modello anti' - voglio ricordare che questo non è sempre il caso .
Se si utilizza il contenitore statico e le importazioni Soddisfare via CompositionInitializer.SatisfyImports si dovrà affrontare il generale dispositivo di anti motivo come CompositionInitializer.Initialize non può essere chiamato più di una volta. Tuttavia, è sempre possibile creare CompositionContainer, aggiungere i cataloghi, e chiamare SatisyImportOnce sul contenitore stesso. In questo caso è possibile utilizzare un nuovo CompositionContainer in ogni prova e farla franca di fronte al comune / dispositivo generale di anti modello
ho bloggato su come fare test di unità (non NUnit, ma funziona lo stesso) con MEF. Il trucco era quello di utilizzare un MockExportProvider e ho creato una base di prova per tutti i miei test per ereditare da.
Questa è la mia funzione AutoWire principale che funziona per test di integrazione e di unità:
protected void AutoWire(MockExportProvider mocksProvider, params Assembly[] assemblies){
CompositionContainer container = null;
var assCatalogs = new List<AssemblyCatalog>();
foreach(var a in assemblies)
{
assCatalogs.Add(new AssemblyCatalog(a));
}
if (mocksProvider != null)
{
var providers = new List<ExportProvider>();
providers.Add(mocksProvider); //need to use the mocks provider before the assembly ones
foreach (var ac in assCatalogs)
{
var assemblyProvider = new CatalogExportProvider(ac);
providers.Add(assemblyProvider);
}
container = new CompositionContainer(providers.ToArray());
foreach (var p in providers) //must set the source provider for CatalogExportProvider back to the container (kinda stupid but apparently no way around this)
{
if (p is CatalogExportProvider)
{
((CatalogExportProvider)p).SourceProvider = container;
}
}
}
else
{
container = new CompositionContainer(new AggregateCatalog(assCatalogs));
}
container.ComposeParts(this);
}
Più informazioni sul mio post: https: / /yoavniran.wordpress.com/2012/10/18/unit-testing-wcf-and-mef/