2010-07-02 12 views
6

Ho una classe A, che ha la seguente:Moq a importazione MEF?

public class A { 
    [Import(typeof(IMyService)] 
    public IMyService MyService { get; set; } 

    public A() { 
     CompositionInitializer.SatisfyImports(this); 
    } 

    public void DoWork() { 
     //Blah 
     MyService.DoIt(); 
     //Blah 
    } 
} 

e un test per testare questo (Dll separata - ovviamente)

[TestMethod] 
public void TestDoWork() { 
    //Blah 
    DoWork(); 
    //Assert assert 
} 

Questa non come il tentativo di chiamare 'MyService' mi dà nulla . Ho poi provato:

[ClassInitialize] 
public void InitialiseClass() { 
    var myService = new Mock<IMyService>(); 
    MyService = myService.Object; 
} 

con 'MyService' dichiarato come:

[Export(typeof(IMyService))] 
public IMyService MyService { get; set; } 

Ma ancora nessuna gioia, mi sto perdendo qualcosa - è anche possibile?

Sto usando SL3, MEF Preview 9 e MOQ.

Qualsiasi aiuto apprezzato!

Acclamazioni

Chris

risposta

4

La classe dovrebbe essere simile a questo:

public class A 
{ 
    private readonly IMyService _myService; 

    [ImportingConstructor] 
    public A(IMyService myService) 
    { 
     _myService = myService; 
    } 

    public void DoWork() { 
     //Blah 
     _myService.DoIt(); 
     //Blah 
    } 
} 

E il test dovrebbe essere simile a questo:

[TestMethod] 
public void DoWork_invokes_IMyService_DoIt() 
{ 
    // arrange mock and system under test 
    var myService = new Mock<IMyService>(); 
    var a = new A(myService.Object); 

    // act  
    a.DoWork(); 

    // assert that DoIt() was invoked 
    myService.Verify(x => x.DoIt()); 
} 

Il fatto che si utilizza MEF non dovrebbe essere importante nel test di unità. Il MEF entra in gioco solo quando si collegano più componenti, il che è esattamente l'opposto di ciò che accade in un test unitario. Un test unitario è per definizione un test di un componente isolato.

Edit: se si preferisce l'iniezione di proprietà, quindi la classe non ha bisogno di un costruttore e la parte di organizzare nel test di unità dovrebbe essere simile a questo, invece:

var myService = new Mock<IMyService>(); 
    var a = new A(); 
    a.MyService = myService.Object; 
+0

OK, ma perché ho bisogno di utilizzare l'importatore del costruttore, la proprietà sta funzionando bene nella mia effettiva implementazione, presumibilmente c'è un percorso per essere in grado di prendere in giro questi tipi di importazioni? –

+1

@Chris: sebbene MEF incoraggi l'iniezione di proprietà, preferisco l'iniezione di costruzione perché in questo modo il compilatore impedisce di creare oggetti con dipendenze mancanti. Permette anche di rendere i campi di dipendenza in sola lettura, quindi non devi pensare a cosa succede se una dipendenza viene sostituita. –

+0

Ho optato per questo metodo, personalmente mi piacerebbe ancora sapere se è possibile prendere in giro l'iniezione di proprietà, ma questo aiuta a risolvere il problema che ho avuto. Cheers. –

1

Dove hai aggiunto [Esporta] all'istanza IMyService, hanno in realtà ha aggiunto che al contenitore composizione? In caso contrario, non prenderà parte alla composizione. Per aggiungere un oggetto deriso al contenitore, effettuare le seguenti operazioni:

container.ComposeExportedValue<IMyService>(mock.Object); 

O semplicemente:

container.ComposeExportedValue(mock.Object); // type inference. 

Fare questo prima di aver creato un'istanza di un consentirà di essere composto dentro la A esempio.

+0

non ho bisogno di aggiungere la concreta attuazione ad un contenitore per farlo funzionare. Ma capisco il tuo punto. Dove stai vedendo il container? –

0

Non deve essere sparando su MEF nei tuoi test unitari. La composizione è ben al di là dell'ambito del test unitario, non dissimile da un contenitore IoC.

dipendenze Insted, si deve iniettare richieste manualmente:

[TestClass] 
public class ATest { 
    Mock<IMyService> myService ; 
    [TestInitialize] 
    public void InitialiseClass() { 
    myService = new Mock<IMyService>(); 
    } 

    [TestMethod] 
    public void DoWorkShouldCallDoIt { 
    A a = new A(); 
    a.MyService = myService.Object; 
    a.DoWork(); 
    myService.Verify(m=>m.DoIt(), Times.Once()); 
    } 
}