Moq'a bir Görevi iade etmesini nasıl söyleyebilirim?


327

İlan eden bir arayüzüm var

Task DoSomethingAsync();

Testlerim için MoqFramework kullanıyorum:

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

Sonra benim testte çağıran kodu yürütmek await DoSomethingAsync(). Ve test bu hatta başarısız oluyor. Neyi yanlış yapıyorum?


5
Bu satırdaki test hatalarını söylediğinizde, hangi hata üretir?
AlSki

@AlSki muhtemelen bir NullReferenceException. Gördüğünüz gibi burada
LuckyLikey

Yanıtlar:


709

Metodunuzda herhangi bir geri arama yok, bu nedenle kullanmak için bir neden yok .CallBack(). .Returns()Ve Görev'i kullanarak istediğiniz değerleri içeren bir Görevi döndürebilirsiniz . Örneğin:

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

2014-06-22 Güncellemesi

Adedi 4.2 bu konuda yardımcı olacak iki yeni uzantı yöntemine sahiptir.

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

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

Güncelleme 2016-05-05

Seth Flowers'ın diğer cevapta belirttiği gibi ReturnsAsync, sadece a döndüren yöntemler için kullanılabilir Task<T>. Yalnızca Görev döndüren yöntemler için,

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

kullanılabilir.

Bu yanıtta gösterildiği gibi , .NET 4.6'da bu basitleştirilmiştir .Returns(Task.CompletedTask);, örneğin:

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

16
.Returns (Task.CompletedTask); cevabım
Todd Vance

8
Adedi çerçevesi güncellemeler aldığı için bu yanıtı güncel tuttuğunuz için teşekkür ederiz!
Jacob Stamm

.Returns(Task.FromResult(default(object))dönüş türü geçersiz olduğunda iyi çalışır. .Returns(Task.FromResult(null as MyType))beklenen dönüş türü null olduğunda iyi çalışır.
Jeremy Ray Brown

1
@JeremyRayBrown açıkladığım gibi, .NET 4.6'da default(object)artık gerekli değil. referans türü olduğu sürece null as MyTypeaynıdır . default(MyType)MyType
Panagiotis Kanavos

40

Benzer Sayı

Kabaca benzeyen bir arayüz var:

Task DoSomething(int arg);

belirtiler

Ünite testim, servisim awaitedçağrıyı test ettiğinde başarısız oldu DoSomething.

Fix

Kabul edilen cevabın aksine, bu senaryoda bu metodu .ReturnsAsync()sizin için çağıramazsınız Setup()çünkü metod genel Taskdeğil, jenerik olmayanı döndürür Task<T>.

Bununla birlikte, .Returns(Task.FromResult(default(object)))testin geçmesine izin vererek kurulumda hala kullanabilirsiniz .


1
Bu konuda sadece bir düşünce, genel olmayan bir görevi (.net 4.6 olmayan) döndürmeniz gerekiyorsa, Görev'e dönmek için kolay bir yol olarak Görev.Delay (1) döndürmeyi düşünürdüm. Ayrıca zaman argümanını artırarak da çalışmayı taklit edebilirsiniz.
stevethethread

26

Yalnızca .Returns(Task.FromResult(0));Geri Aramadan sonra eklemeniz gerekir .

Misal:

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

4

Artık Talentsoft.Moq.SetupAsync paketini de kullanabilirsiniz https://github.com/TalentSoft/Moq.SetupAsync

Burada bulunan cevaplara ve Moq'a önerilen ancak hala burada uygulanmayan fikirlere dayanarak: https://github.com/moq/moq4/issues/384 , asenkron yöntemlerin kurulumunu büyük ölçüde basitleştirin

SetupAsync uzantısıyla yapılan önceki yanıtlarda çok az örnek bulundu:

mock.SetupAsync(arg=>arg.DoSomethingAsync());
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Callback(() => { <my code here> });
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Throws(new InvalidOperationException());
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.