Làm thế nào tôi có thể bảo Moq trả lại một Nhiệm vụ?


327

Tôi đã có một giao diện khai báo

Task DoSomethingAsync();

Tôi đang sử dụng MoqFramework cho các bài kiểm tra của mình:

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

Sau đó, trong thử nghiệm của tôi, tôi thực thi mã mà gọi await DoSomethingAsync(). Và bài kiểm tra chỉ thất bại trên dòng đó. Tôi đang làm gì sai?


5
Khi bạn nói các lỗi kiểm tra trên dòng đó, nó tạo ra lỗi gì?
AlSki

@AlSki có thể là một NullReferenceException. như bạn có thể thấy ở đây
LuckyLikey

Câu trả lời:


706

Phương pháp của bạn không có bất kỳ cuộc gọi lại nào nên không có lý do để sử dụng .CallBack(). Bạn chỉ có thể trả về một Tác vụ với các giá trị mong muốn bằng cách sử dụng .Returns()Task.FromResult , ví dụ:

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

Cập nhật 2014-06-22

Moq 4.2 có hai phương pháp mở rộng mới để hỗ trợ việc này.

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

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

Cập nhật 2016-05-05

Như Seth Hoa đề cập trong câu trả lời khác , ReturnsAsyncchỉ có sẵn cho các phương thức trả về a Task<T>. Đối với các phương thức chỉ trả về một Tác vụ,

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

có thể được sử dụng.

Như được hiển thị trong câu trả lời này , trong .NET 4.6, điều này được đơn giản hóa .Returns(Task.CompletedTask);, ví dụ:

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

16
.Returns (Task.CompletedTask); đó là câu trả lời của tôi
Todd Vance

8
Cảm ơn bạn đã cập nhật câu trả lời này vì khung Moq đã nhận được cập nhật!
Jacob Stamm

.Returns(Task.FromResult(default(object))hoạt động tốt khi loại trả về là void. .Returns(Task.FromResult(null as MyType))hoạt động tốt khi loại trả về dự kiến ​​là null.
Jeremy Ray Brown

1
@JeremyRayBrown như tôi giải thích, trong .NET 4.6 default(object)không còn cần thiết nữa. null as MyTypelà giống như default(MyType)miễn MyTypelà một loại tham chiếu.
Panagiotis Kanavos

40

Vấn đề tương tự

Tôi có một giao diện trông gần giống như:

Task DoSomething(int arg);

Triệu chứng

Kiểm tra đơn vị của tôi không thành công khi dịch vụ của tôi dưới kiểm tra awaitedcuộc gọi đến DoSomething.

Sửa chữa

Không giống như các câu trả lời được chấp nhận, bạn không thể gọi .ReturnsAsync()trên của bạn Setup()của phương pháp này trong kịch bản này, bởi vì phương pháp này trả về không chung chung Task, chứ không phải là Task<T>.

Tuy nhiên, bạn vẫn có thể sử dụng .Returns(Task.FromResult(default(object)))trên thiết lập, cho phép thử nghiệm vượt qua.


1
Chỉ cần suy nghĩ về điều này, nếu bạn cần trả về một tác vụ không chung chung (không phải .net 4.6), tôi sẽ xem xét trả lại Nhiệm vụ.Delay (1) như một cách dễ dàng để trả lại Tác vụ. Bạn cũng có thể bắt chước công việc bằng cách tăng đối số thời gian.
stevethethread

26

Bạn chỉ cần thêm .Returns(Task.FromResult(0));sau khi gọi lại.

Thí dụ:

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

3

Giờ đây, bạn cũng có thể sử dụng gói Talentsoft.Moq.SetupAsync https://github.com/TalentSoft/Moq.SetupAsync

Dựa trên các câu trả lời được tìm thấy ở đây và các ý tưởng được đề xuất cho Moq nhưng vẫn chưa được triển khai ở đây: https://github.com/moq/moq4/issues/384 , đơn giản hóa rất nhiều việc thiết lập các phương thức async

Một số ví dụ được tìm thấy trong các phản hồi trước đó được thực hiện với tiện ích mở rộng SetupAsync:

mock.SetupAsync(arg=>arg.DoSomethingAsync());
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Callback(() => { <my code here> });
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Throws(new InvalidOperationException());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.