Як я можу сказати 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.