2010-01-20 9 views
33

Nel mio lavoro stiamo usando Moq per il mocking e Unity per un container IOC. Sono abbastanza nuovo in questo e non ho molte risorse al lavoro per aiutarmi a determinare le migliori pratiche che dovrei usare.Modo corretto per falsificare gli oggetti repository per i test unitari usando Moq e Unity

Al momento, ho un gruppo di interfacce di repository (Es: IRepository1, IRepository2 ... IRepository4) che un particolare processo deve utilizzare per svolgere il proprio lavoro.

Nel codice reale posso determinare tutti gli oggetti IRepository utilizzando il contenitore IOC e utilizzando il metodo RegisterType().

Sto cercando di capire il modo migliore per essere in grado di testare il metodo che richiede i 4 repository citati.

Stavo pensando che potrei semplicemente registrare una nuova istanza del container Unity IOC e chiamare RegisterInstance sul container per ogni oggetto mock che passa nel valore Mock.Object per ognuno. Sto cercando di rendere riutilizzabile questo processo di registrazione, quindi non devo continuare a ripetere la stessa operazione più volte per ciascun test di unità, a meno che un test unitario non richieda alcuni dati specifici per tornare dal repository. È qui che si trova il problema ... qual è la migliore pratica per impostare i valori previsti su un repository fittizio? Sembra che se chiami RegisterType nel contenitore Unity, perderò un riferimento all'oggetto Mock effettivo e non sarei in grado di sovrascrivere il comportamento.

risposta

55

I test unitari non devono utilizzare il contenitore. L'iniezione delle dipendenze (DI) si presenta in due fasi:

  1. Utilizzare i modelli DI per iniettare dipendenze nei consumatori. Non hai bisogno di un contenitore per farlo.
  2. All'applicazione Composition Root, utilizzare un contenitore DI (o DI di scarsa qualità) per collegare tutti i componenti.

Come non utilizzare alcun DI container a tutti per unità di prova

A titolo di esempio, si consideri una classe che utilizza IRepository1. Usando il modello Costruttore Iniezione, possiamo rendere la dipendenza un invariante della classe.

public class SomeClass 
{ 
    private readonly IRepository1 repository; 

    public SomeClass(IRepository1 repository) 
    { 
     if (repository == null) 
     { 
      throw new ArgumentNullException("repository"); 
     } 

     this.repository = repository; 
    } 

    // More members... 
} 

Si noti che la parola chiave readonly combinata con la clausola Guardia garantisce che il campo repository non è nullo se l'istanza è stata creata un'istanza con successo.

Non è necessario un contenitore per creare una nuova istanza di MyClass. Potete farlo direttamente da una prova di unità utilizzando Moq o di un altro doppio test:

[TestMethod] 
public void Test6() 
{ 
    var repStub = new Mock<IRepository1>(); 
    var sut = new SomeClass(repStub.Object); 
    // The rest of the test... 
} 

Vedi here per ulteriori informazioni ...

Come usare l'unità per il test delle unità

Tuttavia, se è assolutamente necessario utilizzare Unity nei test, è possibile creare il contenitore e utilizzare il metodo RegisterInstance:

[TestMethod] 
public void Test7() 
{ 
    var repMock = new Mock<IRepository1>(); 

    var container = new UnityContainer(); 
    container.RegisterInstance<IRepository1>(repMock.Object); 

    var sut = container.Resolve<SomeClass>(); 
    // The rest of the test... 
} 
+0

Grazie! Stavo solo guardando le cose nel modo sbagliato. –

+0

Ho scremato la tua risposta e stavo pensando se fosse necessario o meno (perché sembrava che stavi raccomandando di usare il contenitore IoC nei test unitari) e poi ho effettivamente letto la tua risposta ... Volevo dire, ecco il mio vergognoso +1 . Se le persone lo trovano utile anche oggi, dovresti usare ** ArgumentNullException (nameof (repository)) ** e non ** ArgumentNullException ("repository") ** - il post è stato scritto 5-6 anni fa quando questa funzione non esisteva . – Margus

Problemi correlati