2010-01-14 7 views
5

Właśnie rozpocząłem wdrażanie testów jednostkowych (przy użyciu xUnit i Moq) w ramach ustalonego już projektu. Projekt szeroko wykorzystuje zastrzyk zależności poprzez pojemnik jedności.Moq i dostęp do wywoływanych parametrów

Mam dwie usługi A i B. Usługa A jest testowana w tym przypadku. Usługa A wywołuje B i przekazuje mu delegata do funkcji wewnętrznej. To "oddzwanianie" jest używane do powiadamiania A, gdy wiadomość została odebrana, którą musi obsłużyć.

Stąd też połączenia (w którym B jest przykładem usług B)

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

W celu przetestowania roboczego A, to musi być w stanie wywołać messageHandler, ponieważ tylko w ten sposób, że obecnie przyjmuje wiadomości.

Czy można to zrobić za pomocą Moq? to znaczy. Czy mogę kpić z usługi B tak, że po wywołaniu RegisterHandler wartość messageHandler jest przekazywana do mojego testu?

Czy muszę przeprojektować to? Czy są jakieś wzorce projektowe, których powinienem używać w tym przypadku? Czy ktokolwiek wie o dobrych zasobach tego typu konstrukcji?

Odpowiedz

9

Można uzyskać instancję zwrotnego (lub dowolny inny parametr wejściowy) za pomocą oddzwanianie (nazwa podobieństwo jest przypadkowe) metoda na 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); 
} 

to działa, gdy ServiceA jest zdefiniowany jako to:

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

Tak można ustawić obiekt Moq, aby reagował na oczekiwane i nieoczekiwane operacje. Oto przykład Visual Studio Test jednostki ...

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