Dariusz Walczak
Dariusz Walczak

Reputation: 4988

Is NUnit's ExpectedExceptionAttribute only way to test if something raises an exception?

I'm completely new at C# and NUnit.

In Boost.Test there is a family of BOOST_*_THROW macros. In Python's test module there is TestCase.assertRaises method.

As far as I understand it, in C# with NUnit (2.4.8) the only method of doing exception test is to use ExpectedExceptionAttribute.

Why should I prefer ExpectedExceptionAttribute over - let's say - Boost.Test's approach? What reasoning can stand behind this design decision? Why is that better in case of C# and NUnit?

Finally, if I decide to use ExpectedExceptionAttribute, how can I do some additional tests after exception was raised and catched? Let's say that I want to test requirement saying that object has to be valid after some setter raised System.IndexOutOfRangeException. How would you fix following code to compile and work as expected?

[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: Thanks for your answers. Today, I've found an It's the Tests blog entry where all three methods described by you are mentioned (and one more minor variation). It's shame that I couldn't find it before :-(.

Upvotes: 5

Views: 1806

Answers (5)

David Arno
David Arno

Reputation: 43254

I've always adopted the following approach:

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

assert.IsFalse(success);

...

Upvotes: 2

Mark Brackett
Mark Brackett

Reputation: 85655

Your preferred syntax:

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

woiuldn't work with C# anyway - the obj.SetValueAt would be evaluated and the result passed to Assert.Raises. If SetValue throws an exception, then you'd never get into Assert.Raises.

You could write a helper method to do it:

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

Which allows the similar syntax of:

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

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1500495

I'm surprised I haven't seen this pattern mentioned yet. David Arno's is very similar, but I prefer the simplicity of this:

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

Upvotes: 13

yfeldblum
yfeldblum

Reputation: 65435

The MbUnit syntax is

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

Upvotes: 4

Cristian Libardo
Cristian Libardo

Reputation: 9258

If you can use NUnit 2.5 there's some nice helpers there.

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

Upvotes: 10

Related Questions