2009-10-22 24 views
168

Làm cách nào để sử dụng Assert.Throws để xác nhận loại ngoại lệ và từ thông báo thực tế.Làm cách nào để sử dụng Assert.Throws để xác nhận loại ngoại lệ?

Something như thế này:

Assert.Throws<Exception>(
    ()=>user.MakeUserActive()).WithMessage("Actual exception message") 

Phương pháp Tôi đang thử nghiệm ném nhiều thông điệp cùng loại, với những thông điệp khác nhau, và tôi cần một cách để kiểm tra rằng thông điệp chính xác được ném tùy thuộc vào ngữ cảnh.

Trả lời

295

Assert.Throws trả lại ngoại lệ được ném cho phép bạn xác nhận về ngoại lệ.

var ex = Assert.Throws<Exception>(() => user.MakeUserActive()); 
Assert.That(ex.Message, Is.EqualTo("Actual exception message")); 

Vì vậy, nếu không có trường hợp ngoại lệ được ném hoặc loại trừ sai được ném, xác nhận Assert.Throws đầu tiên sẽ không thành công. Tuy nhiên, nếu loại trừ đúng loại được ném thì bạn có thể xác nhận về ngoại lệ thực tế mà bạn đã lưu trong biến.

Bằng cách sử dụng mẫu này, bạn có thể khẳng định những thứ khác ngoài thông báo ngoại lệ, ví dụ: trong trường hợp ArgumentException và các dẫn xuất, bạn có thể khẳng định rằng tên tham số là chính xác:

var ex = Assert.Throws<ArgumentNullException>(() => foo.Bar(null)); 
Assert.That(ex.ParamName, Is.EqualTo("bar")); 

Bạn cũng có thể sử dụng API thông thạo để thực hiện điều này khẳng định:

Assert.That(() => foo.Bar(null), 
Throws.Exception 
    .TypeOf<ArgumentNullException>() 
    .With.Property("ParamName") 
    .EqualTo("bar")); 

Một mẹo nhỏ khi khẳng định trên thông báo ngoại lệ là để trang trí phương pháp thử nghiệm với SetCultureAttribute để đảm bảo rằng thư được gửi đang sử dụng văn hóa mong muốn. Điều này xuất hiện nếu bạn lưu trữ các thông báo ngoại lệ của mình dưới dạng tài nguyên để cho phép bản địa hóa.

+0

Điều này thực sự hữu ích cho tôi - Tôi muốn có cách hiển thị lỗi, tôi thậm chí không đọc nếu một giá trị được trả về bằng phương thức Assert.Throws. Cảm ơn – Haroon

+4

+1 Cảm ơn bạn đã hiển thị API thông thạo, vì một số lý do tôi gặp sự cố khi hiểu cách sử dụng nó chỉ từ tài liệu NUnit. – aolszowka

21

Bây giờ, bạn có thể sử dụng các thuộc tính ExpectedException, ví dụ:

[Test] 
[ExpectedException(typeof(InvalidOperationException), 
ExpectedMessage="You can't do that!"] 
public void MethodA_WithNull_ThrowsInvalidOperationException() 
{ 
    MethodA(null); 
} 
+0

Điều này làm tôi băn khoăn một chút khi lần đầu tiên nhìn thấy, bởi vì bài kiểm tra rõ ràng không có khẳng định, đó là một mùi đối với tôi. Đây là một tính năng tốt đẹp, nhưng một trong những nên thảo luận trong nhóm wheter này attribut nên được sử dụng trên Assert.Throws – Marcel

+12

+1 cũng là một cách tốt đẹp để kiểm tra cho trường hợp ngoại lệ. Điều duy nhất cần lưu ý về điều này là về mặt lý thuyết, bất kỳ dòng mã nào ném một InvalidOperationException với thông điệp đó sẽ vượt qua bài kiểm tra, bao gồm mã trong bài kiểm tra của bạn, chuẩn bị dữ liệu/đối tượng thử nghiệm hoặc bất kỳ phương pháp nào khác mà bạn có thể cần thực thi trước một trong những bạn quan tâm đến việc thử nghiệm, có thể dẫn đến kết quả dương tính giả. Tất nhiên, điều đó phụ thuộc vào thông điệp cụ thể như thế nào và loại ngoại lệ bạn đang thử nghiệm. Với 'Assert.Throw' bạn có thể nhắm mục tiêu đường chính xác mà bạn quan tâm. – Nope

+7

Thuộc tính ExpectedException không được chấp nhận trong NUnit 3: https://github.com/nunit/docs/wiki/Breaking-Changes –

2

Đó là một thời gian dài kể từ khi vấn đề này đã được nâng lên, tôi nhận ra, nhưng gần đây tôi chạy vào điều tương tự, và đề xuất chức năng này cho MSTest:

public bool AssertThrows(Action action) where T : Exception 
{ 
try {action();} 
catch(Exception exception) 
{ 
    if (exception.GetType() == typeof(T)) return true; 
} 
return false; 
} 

sử dụng:

Assert.IsTrue(AssertThrows<FormatException>(delegate{ newMyMethod(MyParameter); })); 

Thêm tại đây: http://phejndorf.wordpress.com/2011/02/21/assert-that-a-particular-exception-has-occured/

3

Để mở rộng câu trả lời liên tục và cung cấp thêm các chức năng của NUnit, bạn có thể làm điều này:

public bool AssertThrows<TException>(
    Action action, 
    Func<TException, bool> exceptionCondition = null) 
    where TException : Exception 
{ 
    try 
    { 
     action(); 
    } 
    catch (TException ex) 
    { 
     if (exceptionCondition != null) 
     { 
      return exceptionCondition(ex); 
     } 

     return true; 
    } 
    catch 
    { 
     return false; 
    } 

    return false; 
} 

Ví dụ:

// No exception thrown - test fails. 
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
     () => {})); 

// Wrong exception thrown - test fails. 
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
     () => { throw new ApplicationException(); })); 

// Correct exception thrown - test passes. 
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
     () => { throw new InvalidOperationException(); })); 

// Correct exception thrown, but wrong message - test fails. 
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
     () => { throw new InvalidOperationException("ABCD"); }, 
     ex => ex.Message == "1234")); 

// Correct exception thrown, with correct message - test passes. 
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
     () => { throw new InvalidOperationException("1234"); }, 
     ex => ex.Message == "1234")); 
7
Assert.That(myTestDelegate, Throws.ArgumentException 
    .With.Property("Message").EqualTo("your argument is invalid.")); 
0

Kể từ khi tôi đang bị xáo trộn bởi sự rườm rà của một số mẫu NUnit mới, tôi sử dụng một cái gì đó như thế này để tạo ra mã mà là sạch hơn cho cá nhân tôi:

public void AssertBusinessRuleException(TestDelegate code, string expectedMessage) 
{ 
    var ex = Assert.Throws<BusinessRuleException>(code); 
    Assert.AreEqual(ex.Message, expectedMessage); 
} 

public void AssertException<T>(TestDelegate code, string expectedMessage) where T:Exception 
{ 
    var ex = Assert.Throws<T>(code); 
    Assert.AreEqual(ex.Message, expectedMessage); 
} 

Việc sử dụng là sau đó:

AssertBusinessRuleException(() => service.Create(content), "Name already exists"); 
Các vấn đề liên quan