Можете ли вы помочь мне понять Moq Callback? - PullRequest
84 голосов
/ 14 мая 2010

Используя Moq и посмотрел на Callback, но я не смог найти простой пример, чтобы понять, как его использовать.

У вас есть небольшой рабочий фрагмент, который четко объясняет, как и когда его использовать?

Ответы [ 5 ]

70 голосов
/ 14 мая 2010

трудно победить https://github.com/Moq/moq4/wiki/Quickstart

Если это не достаточно ясно, я бы назвал это ошибкой в ​​документации ...

РЕДАКТИРОВАТЬ: В ответ на ваше разъяснение ...

Для каждого выполняемого вами метода Setup вы можете указать такие вещи, как:

  • ограничения на входы
  • значение для / путь, по которому должно быть получено возвращаемое значение (если оно есть)

Механизм .Callback говорит: «Я не могу описать это прямо сейчас, но когда произойдет такой вызов, перезвони мне, и я сделаю то, что нужно сделать». Как часть той же цепочки беглых вызовов, вы получаете возможность контролировать результат для возврата (если он есть) через .Returns ". В примерах QS, например, они приводят к тому, что возвращаемое значение увеличивается каждый раз.

В общем случае вам не понадобится такой механизм очень часто (в тестовых шаблонах xUnit есть термины для антипаттернов из аналогичной условной логики в тестах), и если есть какой-либо более простой или встроенный способ определить, что вам нужно, это следует использовать в предпочтении.

Часть 3 из 4 в серии Moq Джастина Этереджа охватывает ее, а здесь есть еще один пример обратных вызовов

48 голосов
/ 31 января 2012

Вот пример использования обратного вызова для проверки сущности, отправленной в службу данных, которая обрабатывает вставку.

var mock = new Mock<IDataService>();
DataEntity insertedEntity = null;

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback((DataEntity de) => insertedEntity = de);

Синтаксис альтернативного универсального метода:

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback<DataEntity>(de => insertedEntity = de);

Тогда вы можете проверить что-то вроде

Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");
7 голосов
/ 26 января 2017

В МОК есть два типа Callback. Одно происходит до того, как звонок возвращается; другое происходит после возврата вызова.

var message = "";
mock.Setup(foo => foo.Execute(arg1: "ping", arg2: "pong"))
    .Callback((x, y) =>
    {
        message = "Rally on!";
        Console.WriteLine($"args before returns {x} {y}");
    })
    .Returns(message) // Rally on!
    .Callback((x, y) =>
    {
        message = "Rally over!";
        Console.WriteLine("arg after returns {x} {y}");
    });

В обоих обратных вызовах мы можем:

  1. проверка аргументов метода
  2. метод захвата аргумент
  3. изменить контекстное состояние
3 голосов
/ 10 августа 2017

Callback - это просто средство для выполнения любого пользовательского кода, который вы хотите, когда вызывается один из методов макета. Вот простой пример:

public interface IFoo
{
    int Bar(bool b);
}

var mock = new Mock<IFoo>();

mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
    .Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
    .Returns(42);

var ret = mock.Object.Bar(true);
Console.WriteLine("Result: " + ret);

// output:
// Bar called with: True
// Result: 42

Недавно я столкнулся с интересным вариантом использования. Предположим, вы ожидаете некоторых звонков, но они происходят одновременно. Таким образом, у вас нет возможности узнать порядок, в котором они будут вызываться, но вы хотите знать, что ожидаемые вызовы имели место (независимо от порядка). Вы можете сделать что-то вроде этого:

var cq = new ConcurrentQueue<bool>();
mock.Setup(f => f.Bar(It.IsAny<bool>())).Callback<bool>(cq.Enqueue);
Parallel.Invoke(() => mock.Object.Bar(true), () => mock.Object.Bar(false));
Console.WriteLine("Invocations: " + String.Join(", ", cq));

// output:
// Invocations: True, False

Кстати, не смущайтесь из-за вводящих в заблуждение различий "до Returns" и "после Returns". Это просто техническое различие того, будет ли ваш пользовательский код выполняться после оценки Returns или раньше. В глазах вызывающей стороны оба будут работать до того, как будет возвращено значение. Действительно, если метод void -обратный, вы даже не можете вызвать Returns, и все же он работает так же. Для получения дополнительной информации см https://stackoverflow.com/a/28727099/67824.

1 голос
/ 10 января 2016

Помимо других хороших ответов здесь, я использовал его для выполнения логики, прежде чем выдавать исключение. Например, мне нужно было сохранить все объекты, которые были переданы методу для последующей проверки, и этот метод (в некоторых тестовых примерах) должен был вызвать исключение. Вызов .Throws(...) на Mock.Setup(...) отменяет действие Callback() и никогда не вызывает его. Однако, выбрасывая исключение в обратном вызове, вы все равно можете делать все то хорошее, что может предложить обратный вызов, и все равно генерировать исключение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...