Відповіді:
Важко перемогти https://github.com/Moq/moq4/wiki/Quickstart
Якщо це недостатньо зрозуміло, я б назвав цю помилку в документі ...
EDIT: У відповідь на ваше пояснення ...
Для кожного методу глузування, який Setup
ви виконуєте, ви можете вказати такі речі, як:
.Callback
Механізм каже : «Я не можу описати це прямо зараз, але коли виклик в формі , як це відбувається, передзвони мені , і я буду робити те , що повинно бути зроблено». Як частина одного і того ж ланцюга вільних викликів, ви можете керувати результатом, щоб повернутись (якщо така є) через .Returns
". У прикладах QS приклад полягає в тому, що вони змушують повертати значення щоразу збільшуватися.
Взагалі, вам не знадобиться такий механізм, як це часто (тестові шаблони xUnit мають терміни для антипакетів нерегулярних умовних логічних тестів), і якщо є якийсь простіший або вбудований спосіб встановити те, що вам потрібно, це має бути використовується в перевазі.
Частина 3 із 4 у серії Moq Джастіна Етередже висвітлює його, і тут є ще один приклад зворотних викликів
Простий приклад зворотного дзвінка можна знайти в розділі Використання зворотних дзвінків з повідомленням Moq .
Callback
не має нічого спільного з значенням повернення (якщо ви не зв'язали його через код). По суті, це лише гарантує виклик зворотного дзвінка перед або після кожного виклику (залежно від того, ви прикували його до або після Returns
відповідно), простий і простий.
Ось приклад використання зворотного дзвінка для тестування сутності, надісланої до служби даних, яка обробляє вставку.
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");
It.Is<T>
в Mock.Verify
замість засмічення тесту з темпами. Але +1, бо я думаю, що є багато людей, які найкраще працюватимуть із прикладу.
У 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}");
});
В обох зворотних викликах ми можемо:
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
BTW не плутають оманливу різницю "до Returns
" і "після Returns
". Це лише технічна відмінність того, чи буде працювати ваш власний код після того, Returns
як було оцінено чи раніше. В очах абонента обидва будуть працювати до повернення значення. Дійсно, якщо метод - void
повернення, ви навіть не можете зателефонувати, Returns
але він працює так само. Для отримання додаткової інформації див https://stackoverflow.com/a/28727099/67824 .
Крім інших хороших відповідей тут, я використовував її для виконання логіки перед тим, як кидати виняток. Наприклад, мені потрібно було зберігати всі об'єкти, передані методу для подальшої перевірки, і цей метод (у деяких тестових випадках) необхідний для викиду винятку. Виклик не .Throws(...)
на Mock.Setup(...)
перевизначення в Callback()
дію і не викликає її. Однак, викинувши виняток у межах зворотного виклику, ви все одно можете зробити все хороше, що може запропонувати зворотний дзвінок, і все ж кинути виняток.