Як я можу сказати Moq повернути завдання?


327

У мене є інтерфейс, який заявляє

Task DoSomethingAsync();

Я використовую MoqFramework для своїх тестів:

[TestMethod()]
public async Task MyAsyncTest()
{
   Mock<ISomeInterface> mock = new Mock<ISomeInterface>();
   mock.Setup(arg => arg.DoSomethingAsync()).Callback(() => { <my code here> });
   ...
}

Потім у своєму тесті я виконую код, який викликає await DoSomethingAsync(). І тест просто провалюється на цій лінії. Що я роблю неправильно?


5
Коли ви кажете тестові помилки на цьому рядку, яку помилку він створює?
— AlSki

@AlSki, можливо, NullReferenceException. як ви бачите тут
— LuckyLikey

Відповіді:


709

У вашого методу немає зворотних дзвінків, тому немає ніяких причин використовувати .CallBack(). Ви можете просто повернути Завдання з потрібними значеннями за допомогою .Returns()та Task.FromResult , наприклад:

MyType someValue=...;
mock.Setup(arg=>arg.DoSomethingAsync())        
    .Returns(Task.FromResult(someValue));

Оновлення 2014-06-22

У Moq 4.2 є два нові методи розширення, щоб допомогти у цьому.

mock.Setup(arg=>arg.DoSomethingAsync())
    .ReturnsAsync(someValue);

mock.Setup(arg=>arg.DoSomethingAsync())        
    .ThrowsAsync(new InvalidOperationException());

Оновлення 05.05.2016

Як згадує Сет Квітс в іншій відповіді , ReturnsAsyncдоступний лише для методів, які повертають a Task<T>. Для методів, які повертають лише завдання,

.Returns(Task.FromResult(default(object)))

може бути використано.

Як показано у цій відповіді , у .NET 4.6 це спрощено .Returns(Task.CompletedTask);, наприклад:

mock.Setup(arg=>arg.DoSomethingAsync())        
    .Returns(Task.CompletedTask);

16
.Повернення (Task.CompletedTask); це була моя відповідь
— Todd Vance

8
Дякуємо вам за те, що постійно відповідали за цю відповідь, оскільки система Moq отримує оновлення!
— Якоб Стамм

.Returns(Task.FromResult(default(object))працює добре, коли тип повернення недійсний. .Returns(Task.FromResult(null as MyType))працює добре, коли очікуваний тип повернення є нульовим.
— Джеремі Рей Браун

1
@JeremyRayBrown, як я пояснюю, в .NET 4.6 default(object)більше не потрібен. null as MyTypeтакий же , як до default(MyType)тих пір , як MyTypeце контрольний тип.
— Панайотис Канавос,

40

Аналогічний випуск

У мене є інтерфейс, який виглядав приблизно так:

Task DoSomething(int arg);

Симптоми

Тест мого пристрою не вдалося, коли моя служба перевіряла awaitedдзвінок на DoSomething.

Виправити

На відміну від прийнятої відповіді, ви не можете зателефонувати .ReturnsAsync()на Setup()цей метод у цьому сценарії, оскільки метод повертає негенеріальний Task, а не Task<T>.

Однак ви все одно можете користуватися .Returns(Task.FromResult(default(object)))в налаштуваннях, дозволяючи пройти тест.


1
Поміркувавши над цим, якщо вам потрібно повернути загальне завдання (не .net 4.6), я б розглядав повернення Task.Delay (1) як простий спосіб повернути завдання. Ви також можете імітувати роботу, збільшуючи аргумент часу.
— stevethethread

26

Вам потрібно додати лише .Returns(Task.FromResult(0));після зворотного дзвінка.

Приклад:

mock.Setup(arg => arg.DoSomethingAsync())
    .Callback(() => { <my code here> })
    .Returns(Task.FromResult(0));

4

Тепер ви також можете використовувати пакет Talentsoft.Moq.SetupAsync https://github.com/TalentSoft/Moq.SetupAsync

Що на основі відповідей, знайдених тут, та ідей, запропонованих Moq, але досі ще не реалізованих тут: https://github.com/moq/moq4/isissue/384 , значно спрощує налаштування методів асинхронізації

Кілька прикладів, знайдених у попередніх відповідях, виконаних із розширенням SetupAsync:

mock.SetupAsync(arg=>arg.DoSomethingAsync());
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Callback(() => { <my code here> });
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Throws(new InvalidOperationException());
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.