2010-01-14 4 views
5

Je viens de commencer à implémenter des tests unitaires (en utilisant xUnit et Moq) sur un projet déjà établi. Le projet utilise intensivement l'injection de dépendance via le conteneur unity.Moq et accès aux paramètres appelés

J'ai deux services A et B. Le service A est celui qui est testé dans ce cas. Le service A appelle B et lui donne un délégué à une fonction interne. Ce 'rappel' est utilisé pour notifier A lorsqu'un message a été reçu qu'il doit gérer.

Ainsi, un appel (où b est une instance du service B):

b.RegisterHandler(Guid id, Action<byte[]> messageHandler); 

Afin de tester le service A, je dois être en mesure d'appeler messageHandler, car cela est la seule façon qu'il accepte actuellement messages.

Est-ce que cela peut être fait avec Moq? c'est à dire. Puis-je me moquer du service B, de sorte que lorsque RegisterHandler est appelée, la valeur de messageHandler est transmise à mon test?

Ou ai-je besoin de le reconcevoir? Y a-t-il des modèles de design que je devrais utiliser dans ce cas? Est-ce que quelqu'un sait de bonnes ressources sur ce genre de conception?

Répondre

9

Vous pouvez obtenir une instance de la fonction de rappel (ou tout autre paramètre d'entrée) en utilisant la méthode de rappel (la similitude de nom est accessoire) sur la Mock :

[TestMethod] 
public void Test19() 
{ 
    Action<byte[]> callback = null; 

    var bSpy = new Mock<IServiceB>(); 
    bSpy.Setup(b => b.RegisterHandler(It.IsAny<Guid>(), It.IsAny<Action<byte[]>>())) 
     .Callback((Guid g, Action<byte[]> a) => callback = a); 

    var sut = new ServiceA(bSpy.Object); 
    sut.RegisterCallback(); 

    Assert.AreEqual(sut.Do, callback); 
} 

cela fonctionne lorsque ServiceA est défini comme ceci:

public class ServiceA 
{ 
    private readonly IServiceB b; 

    public ServiceA(IServiceB b) 
    { 
     if (b == null) 
     { 
      throw new ArgumentNullException("b"); 
     } 

     this.b = b; 
    } 

    public void RegisterCallback() 
    { 
     this.b.RegisterHandler(Guid.NewGuid(), this.Do); 
    } 

    public void Do(byte[] bytes) 
    { 
    } 
} 
0

Oui, vous pouvez configurer l'objet Moq pour répondre aux opérations attendues et inattendues. est ici une unité de Visual Studio exemple test ...

[TestMethod] 
public void MyTest() 
    { 
     var moqObject = new Mock<ServiceB>(); 

     // Setup the mock object to throw an exception if a certain value is passed to it... 
     moqObject.Setup(b => b.RegisterHandle(unexpectedValue).Throws(new ArgumentException()); 

     // Or, setup the mock object to expect a certain method call... 
     moqObject.Setup(b => b.RegisterHandle(expectedValue)); 

     var serviceA = new ServiceA(moqObject.Object); 

     serviceA.DoSomethingToTest(); 

     // This will throw an exception if an expected operation didn't happen... 
     moqObject.VerifyAll(); 
    } 
Questions connexes