2012-10-11 22 views
12

Có ai có ví dụ về cách đơn vị kiểm tra phương pháp không đồng bộ trong ứng dụng Windows 8 Metro, để đảm bảo rằng nó ném ngoại lệ bắt buộc?Đơn vị thử nghiệm phương pháp không đồng bộ cho ngoại lệ cụ thể

Với một lớp học với một phương pháp async

public static class AsyncMathsStatic 
{ 
    private const int DELAY = 500; 

    public static async Task<int> Divide(int A, int B) 
    { 
     await Task.Delay(DELAY); 
     if (B == 0) 
      throw new DivideByZeroException(); 
     else 
      return A/B; 
    } 
} 

Tôi muốn viết một phương pháp thử nghiệm bằng cách sử dụng xây dựng Async.ExpectsException mới. Tôi đã thử: -

[TestMethod] 
public void DivideTest1() 
{ 
    Assert.ThrowsException<DivideByZeroException>(async() => { int Result = await AsyncMathsStatic.Divide(4, 0); }); 
} 

nhưng tất nhiên thử nghiệm không chờ phương thức async hoàn thành và do đó kết quả trong thử nghiệm không thành công ngoại lệ chưa được ném.

Trả lời

14

Bạn có thể sử dụng một thử nghiệm đơn vị async Task với thường xuyên ExpectedExceptionAttribute:

[TestMethod] 
[ExpectedException(typeof(DivideByZeroException))] 
public async Task DivideTest1() 
{ 
    int Result = await AsyncMathsStatic.Divide(4, 0); 
} 

Update từ bình luận:ExpectedExceptionAttribute vào các dự án thử nghiệm đơn vị Win8 has been replaced với Assert.ThrowsException, đó là độc đáo không có giấy tờ AFAICT. Đây là a good change design-wise, nhưng tôi không biết tại sao nó chỉ chỉ được hỗ trợ trên Win8.

Vâng, giả định rằng không có async -tương thích Assert.ThrowsException (Tôi không thể nói nếu có một hoặc không phải do thiếu tài liệu), bạn có thể xây dựng một chính mình:

public static class AssertEx 
{ 
    public async Task ThrowsExceptionAsync<TException>(Func<Task> code) 
    { 
    try 
    { 
     await code(); 
    } 
    catch (Exception ex) 
    { 
     if (ex.GetType() == typeof(TException)) 
     return; 
     throw new AssertFailedException("Incorrect type; expected ... got ...", ex); 
    } 

    throw new AssertFailedException("Did not see expected exception ..."); 
    } 
} 

và sau đó sử dụng nó như vậy:

[TestMethod] 
public async Task DivideTest1() 
{ 
    await AssertEx.ThrowsException<DivideByZeroException>(async() => { 
     int Result = await AsyncMathsStatic.Divide(4, 0); 
    }); 
} 

Lưu ý rằng ví dụ của tôi ở đây chỉ thực hiện kiểm tra chính xác loại ngoại lệ; bạn có thể thích cho phép các loại hậu duệ nữa.

Cập nhật 2012-11-29: Mở một UserVoice suggestion để thêm điều này vào Visual Studio.

+0

này hoạt động tốt trong các phiên bản khác của C# , nhưng đã bị xóa khỏi các ứng dụng tàu điện ngầm Windows 8 http: //blogs.msdn.com/b/visualstudioalm/lưu trữ/2012/06/18/visual-studio-2012-rc-what-s-new-in-unit-testing.aspx – Peregrine

+0

Vâng, đó là "thú vị"! Tôi đã cập nhật câu trả lời của mình để cho thấy cách bạn có thể thực hiện 'ThrowsException' tương thích 'async' nếu các bài kiểm tra đơn vị Win8 không hỗ trợ nó. –

+0

Cảm ơn Stephen đã làm việc, mặc dù tôi không thể tin rằng những gì có vẻ như một tính năng mới thanh lịch sẽ yêu cầu như một hack, đặc biệt là nhìn thấy như Windows 8 Metro nơi nhấn mạnh vào các phương pháp async. Hy vọng rằng các tài liệu cuối cùng sau khi phát hành Windows 8 sẽ được sắp tới hơn. – Peregrine

1

Tôi đã gặp phải sự cố tương tự cách đây vài ngày và kết thúc việc tạo ra điều tương tự như câu trả lời của Stephen ở trên. Nó có sẵn dưới dạng Gist. Hy vọng rằng đó là trợ giúp - github gist at có mã đầy đủ và cách sử dụng mẫu.

/// <summary> 
/// Async Asserts use with Microsoft.VisualStudio.TestPlatform.UnitTestFramework 
/// </summary> 
public static class AsyncAsserts 
{ 
    /// <summary> 
    /// Verifies that an exception of type <typeparamref name="T"/> is thrown when async<paramref name="func"/> is executed. 
    /// The assertion fails if no exception is thrown 
    /// </summary> 
    /// <typeparam name="T">The generic exception which is expected to be thrown</typeparam> 
    /// <param name="func">The async Func which is expected to throw an exception</param> 
    /// <returns>The task object representing the asynchronous operation.</returns> 
    public static async Task<T> ThrowsException<T>(Func<Task> func) where T : Exception 
    { 
     return await ThrowsException<T>(func, null); 
    } 

    /// <summary> 
    /// Verifies that an exception of type <typeparamref name="T"/> is thrown when async<paramref name="func"/> is executed. 
    /// The assertion fails if no exception is thrown 
    /// </summary> 
    /// <typeparam name="T">The generic exception which is expected to be thrown</typeparam> 
    /// <param name="func">The async Func which is expected to throw an exception</param> 
    /// <param name="message">A message to display if the assertion fails. This message can be seen in the unit test results.</param> 
    /// <returns>The task object representing the asynchronous operation.</returns> 
    public static async Task<T> ThrowsException<T>(Func<Task> func, string message) where T : Exception 
    { 
     if (func == null) 
     { 
      throw new ArgumentNullException("func"); 
     } 

     string failureMessage; 
     try 
     { 
      await func(); 
     } 
     catch (Exception exception) 
     { 
      if (!typeof(T).Equals(exception.GetType())) 
      { 
       // "Threw exception {2}, but exception {1} was expected. {0}\nException Message: {3}\nStack Trace: {4}" 
       failureMessage = string.Format(
        CultureInfo.CurrentCulture, 
        FrameworkMessages.WrongExceptionThrown, 
        message ?? string.Empty, 
        typeof(T), 
        exception.GetType().Name, 
        exception.Message, 
        exception.StackTrace); 

       Fail(failureMessage); 
      } 
      else 
      { 
       return (T)exception; 
      } 
     } 

     // "No exception thrown. {1} exception was expected. {0}" 
     failureMessage = string.Format(
        CultureInfo.CurrentCulture, 
        FrameworkMessages.NoExceptionThrown, 
        message ?? string.Empty, 
        typeof(T)); 

     Fail(failureMessage); 
     return default(T); 
    } 

    private static void Fail(string message, [CallerMemberName] string assertionName = null) 
    { 
     string failureMessage = string.Format(
      CultureInfo.CurrentCulture, 
      FrameworkMessages.AssertionFailed, 
      assertionName, 
      message); 

     throw new AssertFailedException(failureMessage); 
    } 
} 
0

Hỗ trợ cho việc sử dụng lambdas async bên trong một phương pháp ThrowsException có từ been added in Visual Studio 2012 Update 2, nhưng chỉ cho các dự án thử nghiệm Windows Store.

Bạn có thể sử dụng lớp Microsoft.VisualStudio.TestPlatform.UnitTestFramework.AppContainer.Assert để gọi ThrowsException.

Vì vậy, để sử dụng phương pháp ThrowsException mới, bạn có thể làm một cái gì đó như thế này:

using AsyncAssert = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.AppContainer.Assert; 

[TestMethod] 
public void DivideTest1() 
{ 
    AsyncAssert.ThrowsException<DivideByZeroException>(async() => { 
     int Result = await AsyncMathsStatic.Divide(4, 0); }); 
} 
1
[TestMethod] 
public void DivideTest1() 
{ 
    Func<Task> action = async() => { int Result = await AsyncMathsStatic.Divide(4, 0); }); 
    action.ShouldThrow<DivideByZeroException>(); 
} 

Sử dụng .ShouldThrow() từ FluentAssertions gói NuGet làm việc cho tôi

Các vấn đề liên quan