2008-11-02 24 views
5

Tôi hoàn toàn mới ở C# và NUnit.Là cách duy nhất của ExpitExceptionAttribute chỉ để kiểm tra nếu một cái gì đó làm tăng một ngoại lệ?

Trong Boost.Test có một họ gồm BOOST_*_THROW macro. Trong mô-đun thử nghiệm của Python có phương pháp TestCase.assertRaises.

Theo tôi hiểu, trong C# với NUnit (2.4.8), phương pháp duy nhất thực hiện kiểm tra ngoại lệ là sử dụng ExpectedExceptionAttribute.

Tại sao tôi nên thích ExpectedExceptionAttribute hơn - giả sử - cách tiếp cận của Boost.Test? Lý do gì có thể đứng sau quyết định thiết kế này? Tại sao điều đó tốt hơn trong trường hợp của C# và NUnit?

Cuối cùng, nếu tôi quyết định sử dụng ExpectedExceptionAttribute, làm thế nào tôi có thể làm một số xét nghiệm bổ sung sau khi ngoại lệ được nâng lên và đánh bắt? Hãy nói rằng tôi muốn kiểm tra yêu cầu nói rằng đối tượng phải có giá trị sau khi một số setter nêu ra System.IndexOutOfRangeException. Bạn sẽ sửa mã sau đây như thế nào để biên dịch và hoạt động như mong đợi?

[Test] 
public void TestSetterException() 
{ 
    Sth.SomeClass obj = new SomeClass(); 

    // Following statement won't compile. 
    Assert.Raises("System.IndexOutOfRangeException", 
        obj.SetValueAt(-1, "foo")); 

    Assert.IsTrue(obj.IsValid()); 
} 

Edit: Cảm ơn câu trả lời của bạn. Hôm nay, tôi đã tìm thấy Đó là Bài kiểm trablog entry trong đó tất cả ba phương pháp được mô tả bởi bạn được đề cập (và một biến thể nhỏ hơn). Đó là sự xấu hổ mà tôi không thể tìm thấy nó trước khi :-(

Trả lời

13

tôi ngạc nhiên tôi chưa thấy mô hình này đề cập được nêu ra. David Arno là rất giống nhau, nhưng tôi thích sự đơn giản của điều này:

try 
{ 
    obj.SetValueAt(-1, "foo"); 
    Assert.Fail("Expected exception"); 
} 
catch (IndexOutOfRangeException) 
{ 
    // Expected 
} 
Assert.IsTrue(obj.IsValid()); 
+0

Sẽ không Assert.Fail ("...") đổ bạn ra khỏi thử nghiệm với một AssertionFailedException? –

+1

Có. Tuy nhiên, nếu cuộc gọi đến SetValueAt ném một ngoại lệ (mà chúng ta muốn xảy ra), điều khiển ngay lập tức di chuyển đến khối catch và bỏ qua Assert.Fail, do đó vượt qua bài kiểm tra. Nếu SetValueAt không ném ngoại lệ, thì hành vi không phải là ngoại lệ và thử nghiệm sẽ thất bại. – yfeldblum

+0

Đó là neater hơn cách của tôi để làm điều đó. Tôi sẽ sử dụng cách tiếp cận của bạn trong tương lai :) –

10

Nếu bạn có thể sử dụng NUnit 2.5 có một số đẹp helpers

Assert.That(delegate { ... }, Throws.Exception<ArgumentException>()) 
+1

+1. Tôi thích sử dụng phong cách này là có ít lễ cần thiết để viết các kiểm tra, đặc biệt là nếu bạn cần phải giữ một tài liệu tham khảo để kiểm tra các thông điệp vv Bạn cũng có thể sử dụng var ngoại lệ = Assert.Throws (() => myInstance.DoSomethingInvalid ()); –

2

tôi luôn áp dụng phương pháp sau:..

bool success = true; 
try { 
    obj.SetValueAt(-1, "foo"); 
} catch() { 
    success = false; 
} 

assert.IsFalse(success); 

... 
+0

Cá nhân tôi muốn bắt một ngoại lệ đặc biệt, nhưng điều đó sẽ làm việc ;-p –

+0

@Marc, điểm hợp lệ: nó nên bắt ngoại lệ cụ thể được kiểm tra và cho người khác thông qua để họ xuất hiện như là lỗi chứ không phải là thất bại thử nghiệm. –

4

Các MbUnit cú pháp là

Assert.Throws<IndexOutOfRangeException>(delegate { 
    int[] nums = new int[] { 0, 1, 2 }; 
    nums[3] = 3; 
}); 
2

cú pháp ưa thích của bạn:

Assert.Raises("System.IndexOutOfRangeException", 
       obj.SetValueAt(-1, "foo")); 

woiuldn't làm việc với C# anyway - các obj.SetValueAt sẽ được đánh giá và kết quả được chuyển đến Assert.Raises. Nếu SetValue ném một ngoại lệ, sau đó bạn sẽ không bao giờ nhận được vào Assert.Raises.

Bạn có thể viết một phương pháp helper để làm điều đó:

void Raises<T>(Action action) where T:Exception { 
    try { 
     action(); 
     throw new ExpectedException(typeof(T)); 
    catch (Exception ex) { 
     if (ex.GetType() != typeof(T)) { 
     throw; 
     } 
    } 
} 

nào cho phép các cú pháp tương tự:

Assert.Raises<System.IndexOutOfRangeException>(() => 
    obj.SetValueAt(-1, "foo") 
; 
Các vấn đề liên quan