2012-06-27 26 views
17

Tôi đang cố gắng khám phá cách áp dụng async và chờ từ khóa cho các bài kiểm tra xUnit của mình. Tôi đang sử dụng xUnit 1.9 và Async CTP 1.3. Đây là trường hợp thử nghiệm của tôixUnit và Moq không hỗ trợ async - đang chờ từ khóa

Tôi có một giao diện mà chỉ gọi một phương pháp không đồng bộ

public interface IDoStuffAsync 
{ 
    Task AnAsyncMethod(string value); 
} 

Tôi có một lớp học mà tiêu thụ giao diện và gọi phương thức async

public class UseAnAsyncThing 
{ 
    private readonly IDoStuffAsync _doStuffAsync; 

    public UseAnAsyncThing(IDoStuffAsync doStuffAsync) 
    { 
     _doStuffAsync = doStuffAsync; 
    } 

    public async Task DoThatAsyncOperation(string theValue) 
    { 
     await _doStuffAsync.AnAsyncMethod(theValue); 
    } 
} 

Trong các thử nghiệm của tôi, tôi muốn kiểm tra xem phương thức DoThatAsyncOperation có đang gọi phương thức có giá trị chính xác không vì vậy tôi giả lập giao diện và sử dụng Moq để xác minh cuộc gọi

[Fact] 
    public async void The_test_will_pass_even_though_it_should_fail() 
    { 
     var mock = new Mock<IDoStuffAsync>(); 
     var sut = new UseAnAsyncThing(mock.Object); 

     mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>())); 

     await sut.DoThatAsyncOperation("test"); 

     // This won't throw a Moq.MockExcpetion so the test appears to pass 
     // However it does not run 
     mock.Verify(x => x.AnAsyncMethod("fail")); 
    } 

Thử nghiệm này đang sử dụng các từ khóa asyncawait. Khi nó chạy nó sai đi như Moq nên khẳng định rằng xác minh không thành công. Bất kỳ mã nào sau khi gọi tới số sut.DoThatAsyncOperation("test"); không chạy được

[Fact] 
    public void This_will_work_and_assert_the_reslt() 
    { 
     var mock = new Mock<IDoStuffAsync>(); 
     var sut = new UseAnAsyncThing(mock.Object); 

     mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>())); 

     sut.DoThatAsyncOperation("test").ContinueWith(y => { }); 

     // This won't throw a Moq.MockExcpetion so the test appears to pass 
     // However it does not run 
     mock.Verify(x => x.AnAsyncMethod("fail")); 
    } 

Thử nghiệm này được thiết lập mà không phải chờ đợi và từ khóa không đồng bộ và chuyển tiền phạt.

Đây có phải là hành vi mong đợi đối với xUnit và Moq không?


Cập nhật

Cám ơn lời nhận xét của Stephen tôi quản lý để sửa chữa các thử nghiệm đầu tiên bằng cách làm cho hai thay đổi. Thử nghiệm hiện trả về một nhiệm vụ thay vì void và Mock cũng trả về một nhiệm vụ.

[Fact] 
    public async Task The_test_will_pass_even_though_it_should_fail() 
    { 
     var mock = new Mock<IDoStuffAsync>(); 
     var sut = new UseAnAsyncThing(mock.Object); 

     mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>())).ReturnAsync(true); 

     await sut.DoThatAsyncOperation("test"); 

     // This now fails as it should 
     mock.Verify(x => x.AnAsyncMethod("fail")); 
    } 
+3

Thanks for Update đoạn trên. Các TaskCompletionSource là chìa khóa tôi đã được tìm kiếm trong mocking phương pháp async của tôi bằng cách sử dụng MOQ. – Philippe

+0

Thay vì tạo một TaskCompletionSource rõ ràng, bạn có thể chỉ cần sử dụng Task.FromResult: 'mock.Setup (x => x.AnAsyncMethod (It.IsAny ())). Returns (Task.FromResult (true));' – sapphiremirage

+0

Bạn cũng có thể sử dụng mock.Setup (x => x.AnAsyncMethod (It.IsAny ())). ReturnAsync (true); để tránh thiết lập nhiệm vụ –

Trả lời

14

Thay đổi phương pháp thử đơn vị của bạn để trả lại Task thay vì void và sẽ hoạt động. Hỗ trợ cho async void kiểm tra đơn vị is being considered for a future release.

Tôi mô tả chi tiết why async unit tests don't work by default trên blog của tôi. (Ví dụ về blog của tôi sử dụng MSTest, nhưng các vấn đề tương tự tồn tại trong mọi người thử nghiệm khác, bao gồm xUnit trước 1.9).

+0

Cảm ơn bạn đã tip nhưng điều đó cũng không thành công. Lần này là ném một NullRefException khi chạy phương thức giả. Tôi đoán giả phải trả lại một nhiệm vụ. –

+0

Trong thực tế, dẫn tôi đến câu trả lời. Bây giờ tôi có thể làm bài kiểm tra để vượt qua bằng cách trả lại một TaskCompletionSource từ mô hình. –

+5

Bạn cũng có thể sử dụng 'Task.FromResult' làm viết tắt cho cùng một điều. –

3

Tôi đã cố gắng sử dụng mã từ 'Cập nhật' của bạn, nhưng nó đã dừng ở phương pháp không đồng bộ mà tôi đang chế nhạo.

var tcs = new TaskCompletionSource<T>(); 
    tcs.SetResult(default(T)); 


    mock.Setup(x => x.AnAsyncMethod(It.IsAny<T>())).Returns(tcs.Task); 

Vì vậy, để khắc phục điều đó tôi đã phải thay đổi 'Return' phương pháp:

mock.Setup(x => x.AnAsyncMethod(It.IsAny<T>())).Returns(()=> { return tcs.Task; }); 
Các vấn đề liên quan