Search code examples
c#unit-testingtestingexpected-exception

ExpectedException Assert


I need to write a unit test for the next function and I saw I can use [ExpectedException]

this is the function to be tested.

public static T FailIfEnumIsNotDefined<T>(this T enumValue, string message = null)
        where T:struct
    {
        var enumType = typeof (T);

        if (!enumType.IsEnum)
        {
            throw new ArgumentOutOfRangeException(string.Format("Type {0} is not an Enum, therefore it cannot be checked if it is Defined not have defined.", enumType.FullName));
        } 
        else if (!Enum.IsDefined(enumType, enumValue))
        {
            throw new ArgumentOutOfRangeException(string.Format("{1} Value {0} is not does not have defined value in Enum of type {0}. It should not be...", enumType.FullName, message ?? ""));
        }

        return enumValue;
    }

and here would go the code to test the exceptions that are supposed to be threw

    [TestMethod] 
    [ExpectedException(ArgumentOutOfRangeException(ArgumentException), "message")]
    public void FailIfEnumIsNotDefined_Check_That_The_Value_Is_Not_Enum()
    {
        // PREPARE
        // EXECUTE
        // ASSERT
    }

I don't have idea have to make the assert for the exceptions either.


Solution

  • ExpectedException just asserts that exception of specified type will be thrown by test method:

    [TestMethod] 
    [ExpectedException(typeof(ArgumentOutOfRangeException))]
    public void FailIfEnumIsNotDefined_Check_That_The_Value_Is_Not_Enum()
    {
        // PREPARE
        // EXECUTE
        // NO ASSERT!!
    }
    

    If you want to assert other parameters of exception, then you should use try..catch in your test method:

    [TestMethod]     
    public void FailIfEnumIsNotDefined_Check_That_The_Value_Is_Not_Enum()
    {
        // PREPARE
    
        try
        {
           // EXECUTE
           Assert.Fail()
        }
        catch(Exception exception)
        {        
            // ASSERT EXCEPTION DETAILS
        }
    }
    

    You can write your own method for asserting exception was thrown to avoid repeating same test code over and over again:

    public TException AssertCatch<TException>(Action action)
        where TException : Exception
    {
        try
        {
            action();
        }
        catch (TException exception)
        {
            return exception;
        }
    
        throw new AssertFailedException("Expected exception of type " + 
                                        typeof(TException) + " was not thrown");
    }
    

    Usage:

    var exception = AssertCatch<ArgumentOutOfRangeException>(() => /* EXECUTE */);
    Assert.AreEqual("foo", exception.Message);