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?

Waldemar
sumber
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);
Panagiotis Kanavos
sumber
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.

Bunga Seth
sumber
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));
Diego Torres
sumber
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());
pengguna9812476
sumber