views:

118

answers:

3

Hi,

In the following method, the first catch block is never run, even when an exception of type ExceptionType is thrown:

    /// <summary>
    /// asserts that running the command given throws an exception.
    /// </summary>
    public static void Throws<ExceptionType>(ICommand cmd)
        where ExceptionType : Exception
    {
        // Strangely, using 2 catch blocks on the code below makes the first catch block do nothing.
        try
        {
            try
            {
                cmd.Execute();
            }
            catch (ExceptionType)
            {
                return;
            }
        }
        catch (Exception f)
        {
            throw new AssertionException(cmd.ToString() + " threw an exception of type " + f.GetType() + ".  Expected type was " + typeof(ExceptionType).Name + ".");
        }

        throw new AssertionException(cmd.ToString() + " failed to throw a " + typeof(ExceptionType).Name + ".");
    }

as indicated by the following test:

    [Test]
    public void Test_Throws_CatchesSpecifiedException()
    {
        AssertThat.Throws<AssertionException>(
            new FailureCommand()
        );
    }

using the following class:

class FailureCommand : ICommand
{
    public object Execute()
    {
        Assert.Fail();
        return null;    // never reached.
    }

    public override string ToString()
    {
        return "FailureCommand";
    }
}

giving the following output in NUnit:

TestUtil.Tests.AssertThatTests.Test_Throws_CatchesSpecifiedException: FailureCommand threw an exception of type NUnit.Framework.AssertionException. Expected type was AssertionException.

I also tried using 2 catch blocks for 1 try block (instead of nesting a try/catch within an outer try), but got the same results.

Any ideas as to how to catch the exception specified as a type parameter in one catch block, but catch all other exceptions in the other?

+3  A: 

Works fine for me in this test:

using System;
using System.IO;

class Test
{
    static void Main()
    {
        Throws<ArgumentNullException>(() => File.OpenText(null));
    }

    public static void Throws<ExceptionType>(Action cmd)
        where ExceptionType : Exception
    {
        try
        {
            try
            {
                cmd();
            }
            catch (ExceptionType)
            {
                Console.WriteLine("Caught!");
                return;
            }
        }
        catch (Exception f)
        {
            Console.WriteLine("Threw an exception of type " + f.GetType() 
                + ".  Expected type was " + typeof(ExceptionType) + ".");
        }

        Console.WriteLine("No exception thrown");
    }
}

How certain are you that the two AssertionException exceptions are identical? Are they definitely in the same namespace (print typeof(ExceptionType) rather than just the Name property)? Are they from the same assembly? I wouldn't be surprised to find some oddities due to multiple test framework versions coexisting...

Try it with an exception other than AssertionException to make life simpler.

Jon Skeet
A: 

I haven't debugged this code or looked at it too long but could it be that you first "return" statement is causing the code to HALT and leave the method. Therefore, the exception is "caught" or "handled" (however you look at it) and the outer try/catch block is never executed.

Are you trying to do this?

try        
{            
    try            
    {                
     cmd.Execute();            
    }            
    catch (ExceptionType)            
    {                
     throw;
    }        
}        
catch (Exception f)        
{            
    throw new AssertionException(cmd.ToString() + " threw an exception of type " + f.GetType() + ".  Expected type was "  + typeof(ExceptionType).Name + ".");        
}
masenkablast