2014-04-07 9 views
5

Lo scenario che attualmente dispongo è che sto scrivendo un test unitario per un codice che utilizza un'altra libreria di codice che utilizza l'iniezione di dipendenza e fornisce un UnitContainerExtension per l'avvio di tutte le classi concrete richiesto dalla biblioteca. Tuttavia nel mio test unitario voglio essere in grado di prendere in giro uno o due tipi registrati. Ora, in teoria, in base a tutto il post che ho visto, non ci dovrebbero essere problemi con la registrazione e quindi la registrazione di un nuovo tipo. Quest'ultima definizione/mappatura sostituisce la prima.Sostituzione del tipo registrato in Unity RegisterType <TFrom, TTo> vs ReigsterType <T>

Tuttavia questo non sembra funzionare nella pratica. Ora potrei semplicemente copiare l'elenco di tipo di registrazione dall'estensione delle librerie e ommit/modificare quelli che ho bisogno di prendere in giro. Tuttavia ho pensato che questo non mi sembra giusto e forse mi manca qualcosa.

Il seguente è un esempio del codice (che è stato semplificato e aveva l'UnitContainerExtension inline):

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Microsoft.Practices.Unity; 
using Moq; 

namespace UnityTest 
{ 
    class Program 
    { 
     private static IFooBar _mockFooBar; 

     public static IFooBar MockFooBar 
     { 
      get 
      { 
       return _mockFooBar ?? (_mockFooBar = Mock.Of<IFooBar>(fb => fb.Test(It.IsAny<string>()) == "I am mockery of FooBar!")); 
      } 
     } 

     static void Main(string[] args) 
     { 
      UnityContainer container = new UnityContainer(); 

      //Registration of concrete class done inside extension 
      container.RegisterType<IFooBar, FooBar>(); 

      //Re-registering 
      container.RegisterType<IFooBar>(new InjectionFactory(uc => MockFooBar)); 

      //This should resolve to the mocked foobar but doesn't 
      Console.WriteLine(container.Resolve<IFooBar>().Test("I am the concrete FooBar!")); 
      Console.ReadLine(); 
     } 

     public interface IFooBar 
     { 
      string Test(string text); 
     } 

     public class FooBar : IFooBar 
     { 
      public string Test(string text) 
      { 
       // Some concrete code 
       return text; 
      } 
     } 
    } 
} 

Tuttavia il tipo IFooBar risolve alla classe FooBar concreta anziché la versione deriso.

ho il sospetto che chiamare RegesterType <T> invece di RegisterType < TFrom, TTO > quando ri-registrazione potrebbe essere il problema.

La seguente è una schermata del contenitore in fase di esecuzione dopo la seconda chiamata a RegisterType: enter image description here

anche lo stesso sembra accadere con un'altra classe 'non deriso', che non è così sorprendente come si spera Unità non sta guardando il tipo di mappato all'oggetto.

Utilizzando il seguente fonte esempio modificato:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Microsoft.Practices.Unity; 
using Moq; 

namespace UnityTest 
{ 
    class Program 
    { 
     private static IFooBar _mockFooBar; 

     public static IFooBar MockFooBar 
     { 
      get 
      { 
       return _mockFooBar ?? (_mockFooBar = Mock.Of<IFooBar>(fb => fb.Test(It.IsAny<string>()) == "I am mockery of FooBar!")); 
      } 
     } 

     static void Main(string[] args) 
     { 
      UnityContainer container = new UnityContainer(); 

      //Registration of concrete class done inside extension 
      container.RegisterType<IFooBar, FooBar>(); 

      //Re-registering 
      container.RegisterType<IFooBar>(new InjectionFactory(uc => MockFooBar)); 

      //Re-registering 
      container.RegisterType<IFooBar>(new InjectionFactory(uc => new FooBar2())); 

      //This should resolve to the mocked foobar but doesn't 
      Console.WriteLine(container.Resolve<IFooBar>().Test("I am the original FooBar!")); 
      Console.ReadLine(); 
     } 

     public interface IFooBar 
     { 
      string Test(string text); 
     } 

     public class FooBar : IFooBar 
     { 
      public string Test(string text) 
      { 
       // Some concrete code 
       return text; 
      } 
     } 


     public class FooBar2 : IFooBar 
     { 
      public string Test(string text) 
      { 
       // Some concrete code 
       return "FooBar 2.0"; 
      } 
     } 
    } 
} 

dà gli stessi risultati - questa è la prima registrazione viene utilizzato su qualsiasi di quelli successivi:

enter image description here

+0

hai usato un debugger per vedere se il metodo factory viene richiamato? – mmilleruva

+0

Sì, un punto di interruzione sulla proprietà MockFooBar non viene toccato. Inoltre, se ispezionate il container in fase di esecuzione e date un'occhiata alla proprietà Registrations, potete vedere che la registrazione sta ancora puntando alla classe concreta. –

risposta

9

direi che questo conta come un bug in Unity, ma se hai già registrato l'interfaccia su un tipo concreto, la registrazione di sovrascrittura deve contenere un tipo concreto anche se lo standard è stato soddisfatto dalla fabbrica hod è usato.

Nel tuo esempio:

 container.RegisterType<IFooBar, FooBar>(); 

     //Re-registering 
     container.RegisterType<IFooBar, FooBar>(new InjectionFactory(uc => MockFooBar)); 

ho verificato che il tipo nella vostra registrazione sovrascrivendo potrebbe essere qualsiasi tipo concreto implementando l'interfaccia.

+0

Scusate per la confusione che stavo abusando del termine classe concreta, che è normalmente usato per riferirsi a una classe non astratta. Stavo cercando di differire tra l'effettiva implementazione dell'interfaccia e la classe proxy generata da Moq (che di per sé è una classe concreta). –

+0

@TomMaher: il proxy È una classe concreta e se compili ed esegui il mio snippet, vedrai che sebbene la registrazione registri di mappare 'IFooBar' su' FooBar', ** il tuo ** factory è usato e la registrazione vera e propria come previsto. –

+0

Ahhhh - ho appena visto la differenza nel tuo codice. Si sta utilizzando il metodo RegisterType su RegisterType . Interessante ... –