2010-07-02 7 views
6

J'ai une classe A qui a les éléments suivants:Moq une importation MEF?

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

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

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

Et un test pour tester cette (séparée dll - évidemment)

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

Cela échoue comme une tentative d'appeler 'MyService' me donne null . J'ai ensuite essayé:

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

avec 'MyService' avoués comme:

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

Mais toujours pas de joie, que je manque quelque chose - est-ce possible? J'utilise SL3, MEF Preview 9 et MOQ.

Toute aide appréciée!

Vive

Chris

Répondre

4

Votre classe devrait ressembler à ceci:

public class A 
{ 
    private readonly IMyService _myService; 

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

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

Et votre test devrait ressembler à ceci:

[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()); 
} 

Le fait que vous utilisez MEF ne devrait pas être important dans les tests unitaires. Le MEF ne joue qu'un rôle lors du câblage de nombreux composants, ce qui est exactement le contraire de ce qui se passe dans un test unitaire. Un test unitaire est par définition un test d'un composant isolé.

Modifier: si vous préférez l'injection de propriété, votre classe n'a pas besoin d'un constructeur et organiser une partie dans votre test unitaire devrait ressembler à ceci:

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

OK, mais pourquoi ai-je besoin d'utiliser l'importateur constructeur, la propriété fonctionne bien dans ma mise en œuvre réelle, il existe probablement une route pour être en mesure de se moquer de ces types d'importations? –

+1

@Chris: bien que MEF encourage l'injection de propriétés, je préfère l'injection de construction car ainsi le compilateur vous empêche de créer des objets avec des dépendances manquantes. Cela vous permet également de rendre les champs de dépendance en lecture seule, vous n'avez donc pas à penser à ce qui se passe si une dépendance est remplacée. –

+0

J'ai opté pour cette méthode, personnellement j'aimerais toujours savoir si vous pouvez simuler l'injection de propriété, mais cela aide à résoudre le problème que j'avais. Cheers. –

1

Si vous avez ajouté [Exporter] à votre instance IMyService, avez-vous réellement ajouté que dans le récipient de composition? Sinon, il ne participera pas à la composition. Pour ajouter un objet moqué au conteneur, procédez comme suit:

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

Ou tout simplement:

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

Faire cela avant que vous ayez créé une instance de lui permettra d'être composé à l'intérieur de votre A exemple.

+0

Je ne ont pas besoin d'ajouter la mise en œuvre concrète à un conteneur pour le faire fonctionner. Mais je vois votre point. Où voyez-vous le conteneur? –

0

Vous ne devriez pas être tiriez MEF dans vos tests unitaires. La composition va bien au-delà de la portée du test unitaire, pas très différent d'un conteneur IoC.

Insted, vous devez injecter manuellement les dépendances nécessaires:

[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()); 
    } 
}