Moq и доступ к вызываемым параметрам - PullRequest
5 голосов
/ 14 января 2010

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

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

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

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

Чтобы протестировать службу A, мне нужно иметь возможность позвонить messageHandler, поскольку это единственный способ, которым она в настоящее время принимает сообщения.

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

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

Ответы [ 2 ]

9 голосов
/ 14 января 2010

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

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

[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();
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...