2015-07-09 25 views
18

Tôi đang cố gắng xác minh rằng một phương thức không đồng bộ được gọi với thông số chính xác. Tuy nhiên, tôi nhận được cảnh báo:NSubstitute - Đã nhận cho không đồng bộ - cảnh báo “cuộc gọi không được chờ đợi”

"Vì cuộc gọi này không được chờ đợi, việc thực hiện phương pháp hiện tại vẫn tiếp tục trước khi cuộc gọi kết thúc. Hãy xem xét áp dụng toán tử" chờ đợi "cho kết quả cuộc gọi". Cảnh báo này xuất hiện trên dòng mã bên dưới chú thích //Assert (bên dưới).

thử nghiệm của tôi sử dụng NSubstitute là như sau:

[Test] 
public async Task SimpleTests() 
{ 
    //Arrange 
    var request = CreateUpdateItemRequest(); 

    databaseHelperSub.ExecuteProcAsync(Arg.Any<DatabaseParams>()).Returns(Task.FromResult((object)null)); 

    //Act  
    await underTest.ExecuteAsync(request); 

    //Assert 
    databaseHelperSub.Received().ExecuteProcAsync(Arg.Is<DatabaseParams>(
    p => p.StoredProcName == StoredProcedureName 
     && p.Parameters[0].ParameterName == "Param1" 
     && p.Parameters[0].Value.ToString() == "Value1" 
     && p.Parameters[1].ParameterName == "Param2" 
     && p.Parameters[1].Value.ToString() == "Value2")); 
} 

Các đơn vị theo phương pháp kiểm tra underTest.ExecuteAsync(request) gọi ExecuteProcedureAsync và thực hiện các công chờ đợi:

var ds = await DatabaseHelper.ExecuteProcAsync(dbParams); 

Do thực tế rằng với NSubstitute, các Received() được yêu cầu sau khi thực hiện các đơn vị được kiểm tra. Trong khi ở RhinoMocks, bạn có thể mong đợi để có cuộc gọi xảy ra trước khi thiết bị đang được kiểm tra được thực hiện. RhinoMocks có thể trả về Task.FromResult() trong khi NSubstitute thì không.

Các RhinoMocks tương đương mà làm việc là thế này:

[Test] 
     public async Task SimpleTest() 
     { 
      // Arrange 
      var request = new UpdateItemRequest(); 

      databaseHelperMock.Expect(m => m.ExecuteProcAsync(Arg<DatabaseParams>.Matches(
       p => p.StoredProcName == StoredProcedureName 
        && p.Parameters[0].ParameterName == "Param1" 
        && p.Parameters[0].Value.ToString() == "Value1" 
        && p.Parameters[1].ParameterName == "Param2" 
        && p.Parameters[1].Value.ToString() == "Value2 
       ))).Return(Task.FromResult<object>(null)); 

      // Act 
      await underTest.ExecuteAsync(request); 

     } 

Tôi đã thấy rằng có một cách giải quyết khác, nơi bạn có thể thêm một phương pháp khuyến nông để loại bỏ vấn đề này:

public static class TestHelper 
    { 
    public static void IgnoreAwait(this Task task) 
    { 

    } 
    } 

Ý nghĩa dòng thử nghiệm của tôi cho NSubstitute có thể được thực hiện như sau và cảnh báo biến mất:

databaseHelperSub.Received().ExecuteProcAsync(Arg.Is<DatabaseParams>(
     p => p.StoredProcName == StoredProcedureName 
      && p.Parameters[0].ParameterName == "Param1" 
      && p.Parameters[0].Value.ToString() == "Value1" 
      && p.Parameters[1].ParameterName == "Param2" 
      && p.Parameters[1].Value.ToString() == "Value2")).IgnoreAwait(); 
    } 

Tuy nhiên, tôi cho rằng phải có một giải pháp tốt hơn ngoài kia cho điều này?

+0

Đây là một trình biên dịch * * cảnh báo nói rằng bạn quên đặt một 'await' trước một phương pháp không đồng bộ. Tại sao bạn không đơn giản đặt 'await' vào dòng sau' // Assert'? –

+2

Nếu bạn chờ trước cuộc gọi. Kiểm tra không thành công vì nó nhận được một ngoại lệ tham chiếu null. – JBond

+3

NSubstitute hiện không có cách xử lý tốt hơn. Xem lời giải thích của Jake ở đây: http://stackoverflow.com/a/31021430/906 Có thể đáng để thay đổi NSub, tôi đã tạo ra một vấn đề ở đây: https://github.com/nsubstitute/NSubstitute/issues/190 –

Trả lời

15

Ngay sau khi bạn nâng cấp lên phiên bản 1.9.0 hoặc cao hơn, bạn sẽ có thể sử dụng await mà không nhận một NullReferenceException.

+0

Bạn có biết khi nào 1.8.3 có thể được phát hành không? Có vấn đề này tại thời điểm – levelnis

+0

Tôi không biết. Bạn nên hỏi David Tchepak mặc dù (thông qua https://github.com/nsubstitute/NSubstitute/issues có thể). Anh ấy là người bảo trì của NSubstitute. –

+1

@levelnis Chỉ để bạn biết. V1.9.0 của NSubstitute đã được phát hành. Trong đó có các cải tiến sẽ giải quyết vấn đề trong câu hỏi tràn ngăn xếp này. – JBond

5

Bất cứ khi nào vị từ Received() quá phức tạp hoặc không phù hợp với NSubstitute, bạn luôn có thể thu thập các arg được chỉ định bằng cách sử dụng callbacks qua When().Do() hoặc .AndDoes(). Đối với trường hợp sử dụng của bạn mà có thể đi một cái gì đó như thế này

DatabaseParams receivedParms = null; 
databaseHelperSub.ExecuteProcAsync(Arg.Any<DatabaseParams>()) 
    .Returns(Task.FromResult((object)null)) 
    .AndDoes(x => receivedParms = x.Arg<DatabaseParams>); 

//Act  
await underTest.ExecuteAsync(request); 

//Assert 
receivedParms.Should().NotBeNull(); 
// assert your parms... 
0

Jake Ginnivan answer giải thích rằng đối với Đang chờ nhận được là không bắt buộc, tuy nhiên trình biên dịch không hiểu nó.

Bạn có thể yên tâm ngăn chặn cảnh báo

#pragma warning disable 4014 //for .Received await is not required, so suppress warning “Consider applying the 'await' operator” 
    _service.Received(totalNumber).MyMethod(Arg.Any<ParamType>()); 
#pragma warning restore 4014 
Các vấn đề liên quan