2010-01-14 6 views
5

Я только начал внедрять модульные тесты (используя xUnit и Moq) по уже созданному моему проекту. В проекте широко используется инъекция зависимостей через контейнер единства.Moq и доступ к вызываемым параметрам

У меня есть две службы A и B. Сервис A - это тот, который тестируется в этом случае. Служба A вызывает B и дает ей делегат для внутренней функции. Этот «обратный вызов» используется для уведомления A, когда сообщение получено, которое оно должно обрабатывать.

Следовательно, А звонки (где Ь является экземпляром службы B):

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

Для того, чтобы проверить услугу А, мне нужно, чтобы быть в состоянии назвать messageHandler, так как это единственный способ в настоящее время он принимает Сообщения.

Можно ли это сделать с помощью Moq? то есть. Могу ли я посмеяться над сервисом B, чтобы при вызове RegisterHandler значение messageHandler было передано в мой тест?

Или мне нужно переконфигурировать это? Существуют ли какие-либо шаблоны проектирования, которые я должен использовать в этом случае? Кто-нибудь знает какие-либо хорошие ресурсы для такого дизайна?

ответ

9

Вы можете получить экземпляр обратного вызова (или любой другой входной параметр), используя обратный вызов (имя сходство случайно) метод на 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); 
} 

Это работает, когда ServiceA определяется следующим образом:

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

Да, вы можете настроить объект Moq для ответа на ожидаемые и неожиданные операции. Вот Визуальный пример Studio Test Unit ...

[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(); 
    } 
Смежные вопросы