Cerco di utilizzare il kernel DI direttamente nel mio codice il meno possibile, facendo invece affidamento sull'iniezione del costruttore (o proprietà in casi selezionati, come le classi Attribute
). Dove devo, tuttavia, utilizzo un livello di astrazione, in modo da poter impostare l'oggetto del kernel DI, rendendolo mockable nei test unitari.
Ad esempio:
public interface IDependencyResolver : IDisposable
{
T GetImplementationOf<T>();
}
public static class DependencyResolver
{
private static IDependencyResolver s_resolver;
public static T GetImplementationOf<T>()
{
return s_resolver.GetImplementationOf<T>();
}
public static void RegisterResolver(IDependencyResolver resolver)
{
s_resolver = resolver;
}
public static void DisposeResolver()
{
s_resolver.Dispose();
}
}
Utilizzando un modello come questo, è possibile impostare la IDependencyResolver
dal test di unità chiamando RegisterResolver
con un'implementazione finto o falso che restituisce qualsiasi oggetto che si desidera, senza dover cablare moduli pieni . Ha anche un vantaggio secondario di astrarre il codice da un particolare contenitore IoC, se si sceglie di passare a uno diverso in futuro.
Naturalmente, vorresti anche aggiungere ulteriori metodi a IDependencyResolver
come le tue esigenze dettano, sto solo includendo le basi qui come esempio. Sì, questo richiederebbe quindi di scrivere un wrapper super semplice attorno al kernel di Ninject che implementa anche IDependencyResolver
.
Il motivo per cui si desidera eseguire questa operazione è che i test di unità devono solo testare una cosa e utilizzando il proprio contenitore IoC, si sta davvero esercitando più della classe in prova, che può portare a falsi negativi che rendono i test fragili e (ancora più importante) scuotono la fiducia degli sviluppatori nella loro accuratezza nel tempo. Questo può portare a testare l'apatia e l'abbandono poiché diventa possibile che i test falliscano ma il software funzioni ancora correttamente ("non preoccuparti, quello fallisce sempre, non è un grosso problema").
+1 per il modello resolver, tuttavia, VERAMENTE, provare a utilizzare l'iniezione del costruttore in MyClass che richiede IDepend. in questo modo, i tuoi test unitari non hanno nemmeno bisogno del tuo contenitore IoC. –
Perché non fare qualcosa di più semplice come eseguire l'override dei binding in questo modo ... var kernel = new StandardKernel (new ProductionModule (config)); kernel.Rebind() .To () .InSingletonScope(); –
È possibile sovrascrivere i collegamenti, ma i test eseguono anche il test del contenitore DI, insieme all'unità sottoposta a test. In alcune situazioni, questo non è un grosso problema ma può portare a falsi negativi ed erodere la fede nella suite di test come delineato nella mia risposta. – krohrbaugh