Bagaimana saya bisa memberi tahu Moq untuk mengembalikan Tugas?


327

Saya punya antarmuka yang menyatakan

Task DoSomethingAsync();

Saya menggunakan MoqFramework untuk pengujian saya:

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

Kemudian dalam pengujian saya, saya menjalankan kode yang memanggil await DoSomethingAsync(). Dan tes itu gagal pada garis itu. Apa yang saya lakukan salah?


5
Ketika Anda mengatakan kesalahan pengujian pada baris itu, kesalahan apa yang dihasilkannya?
AlSki

@AlSki mungkin sebuah NullReferenceException. seperti yang Anda lihat di sini
LuckyLikey

Jawaban:


709

Metode Anda tidak memiliki panggilan balik sehingga tidak ada alasan untuk menggunakannya .CallBack(). Anda cukup mengembalikan Tugas dengan menggunakan nilai-nilai yang diinginkan menggunakan .Returns()dan Task.From , misalnya:

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

Pembaruan 2014-06-22

Moq 4.2 memiliki dua metode ekstensi baru untuk membantu ini

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

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

Perbarui 2016-05-05

Seperti Seth Bunga menyebutkan dalam jawaban lain , ReturnsAsynchanya tersedia untuk metode yang mengembalikan a Task<T>. Untuk metode yang hanya mengembalikan Tugas,

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

dapat digunakan.

Seperti yang ditunjukkan dalam jawaban ini , dalam. NET 4.6 ini disederhanakan menjadi .Returns(Task.CompletedTask);, misalnya:

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

16
.Returns (Task.CompletedTask); itulah jawaban saya
Todd Vance

8
Terima kasih karena terus memperbarui jawaban ini karena kerangka kerja Moq telah menerima pembaruan!
Jacob Stamm

.Returns(Task.FromResult(default(object))berfungsi dengan baik ketika jenis kembali tidak berlaku. .Returns(Task.FromResult(null as MyType))berfungsi dengan baik ketika tipe pengembalian yang diharapkan adalah nol.
Jeremy Ray Brown

1
@ JeremyRayBrown seperti yang saya jelaskan, di .NET 4.6 default(object)tidak lagi diperlukan. null as MyTypesama dengan default(MyType)asalkan MyTypemerupakan tipe referensi.
Panagiotis Kanavos

40

Masalah serupa

Saya memiliki antarmuka yang mirip:

Task DoSomething(int arg);

Gejala

Uji unit saya gagal ketika layanan saya sedang menguji awaitedpanggilan ke DoSomething.

Memperbaiki

Berbeda dengan jawaban yang diterima, Anda tidak dapat memanggil .ReturnsAsync()pada Anda Setup()dari metode ini dalam skenario ini, karena metode mengembalikan non-generik Task, bukan Task<T>.

Namun, Anda masih dapat menggunakan .Returns(Task.FromResult(default(object)))pada pengaturan, memungkinkan tes untuk lulus.


1
Pikirkan saja ini, jika Anda perlu mengembalikan tugas non-generik (non .net 4.6), saya akan mempertimbangkan mengembalikan Task.Delay (1) sebagai cara mudah untuk mengembalikan Tugas. Anda juga dapat meniru kerja juga dengan meningkatkan argumen waktu.
stevethethread

26

Anda hanya perlu menambahkan .Returns(Task.FromResult(0));setelah Callback.

Contoh:

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

4

Sekarang Anda juga dapat menggunakan paket Talentsoft.Moq.SetupAsync https://github.com/TalentSoft/Moq.SetupAsync

Yang berdasarkan jawaban yang ditemukan di sini dan ide-ide yang diajukan ke Moq tetapi masih belum diimplementasikan di sini: https://github.com/moq/moq4/issues/384 , sangat menyederhanakan pengaturan metode async

Beberapa contoh ditemukan dalam respons sebelumnya yang dilakukan dengan ekstensi SetupAsync:

mock.SetupAsync(arg=>arg.DoSomethingAsync());
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Callback(() => { <my code here> });
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Throws(new InvalidOperationException());
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.