2008-11-02 4 views
5

Я совершенно новый на C# и NUnit.Является ли NUnit ExpectedExceptionAttribute единственным способом проверки, если что-то вызывает исключение?

В Boost.Test есть семейство BOOST_*_THROW макросов. В тестовом модуле Python существует метод TestCase.assertRaises.

Насколько я понимаю, в C# с NUnit (2.4.8) единственным методом проверки исключений является использование ExpectedExceptionAttribute.

Почему я должен отдавать предпочтение ExpectedExceptionAttribute over - допустим - подход Boost.Test? Какие рассуждения могут стоять за этим проектным решением? Почему это лучше в случае C# и NUnit?

Наконец, если я решил использовать ExpectedExceptionAttribute, как я могу сделать некоторые дополнительные тесты после того, как исключение было поднято и выловлено? Предположим, что я хочу проверить требование, говоря, что объект должен быть действительным после того, как какой-либо сеттер поднял System.IndexOutOfRangeException. Как бы вы исправили следующий код для компиляции и работы, как ожидалось?

[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: Спасибо за ваши ответы. Сегодня я нашел Это тестыblog entry, где упоминаются все три описанных вами метода (и еще одно незначительное изменение). Это позор, что я не мог найти его, прежде чем :-(

ответ

13

Я удивлен, что я не видел эту модель упоминается еще. Дэвид Arno очень похож, но я предпочитаю простоту этого:

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

Если вы можете использовать NUnit 2.5 есть некоторые интересные helpers там

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

+1. Я предпочитаю использовать этот стиль, поскольку для написания теста требуется меньше церемоний, особенно если вам нужно сохранить ссылку для проверки сообщений и т. Д. Вы также можете использовать var exception = Assert.Throws (() => myInstance.DoSomethingInvalid ()); – 2010-06-27 02:35:30

2

Я всегда был принят следующий подход:..

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

assert.IsFalse(success); 

... 
синтаксис
+0

Лично я поймаю конкретное исключение, но это сработает; -p – 2008-11-03 04:58:19

+0

@Marc, действительная точка: он должен поймать конкретное исключение под тестированием и позволить другим пропустить, чтобы они отображались как ошибки, а не ошибки тестирования. – 2008-11-03 08:43:54

4

MbUnit является

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

Ваш предпочтительный синтаксис:

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

woiuldn't работы с C# в любом случае - obj.SetValueAt будет оцениваться и результат передан в Assert.Raises. Если SetValue выбрасывает исключение, вы никогда не попадете в Assert.Raises.

Вы можете написать вспомогательный метод, чтобы сделать это:

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

который позволяет подобный синтаксис:

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