ExpectedException Assert
Asked Answered
E

5

11

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.

Eductive answered 10/12, 2013 at 12:7 Comment(4)
Use Assert.Throws() instead of ExpectedException, as this attribute makes the test pass if the exception occurred in any part of the test method code. Assert.Throws allows to test exact place of code where the exception occurs.Twinge
@sthotakura MSTest does not have Assert.Throws unless you write a custom one, Which is the preferred MSTest exception handling anyway. Similar to NUnit :) There is a link in my answerBaucom
If this is Microsofts own testing framework in the Microsoft.VisualStudio.TestTools.UnitTesting namespace, see ExpectedExceptionAttribute class.Garrygarson
@sthotakura, Spock I provided a sample implementation for Throws in my answer as well: https://mcmap.net/q/960416/-expectedexception-assert.Flake
W
27

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);
Wapiti answered 10/12, 2013 at 12:9 Comment(0)
A
3

Assert the exception is throw with the correct exception message with :

var ex = Assert.Throws<Exception>(() => _foo.DoSomething(a, b, c));
Assert.That(ex.Message, Is.EqualTo("Your exception message"));
Adulation answered 16/11, 2014 at 13:10 Comment(0)
M
2

You must use ExpectedException differently:

[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void MyTestSomething() 

and then code your test so that the expected exception gets thrown.

Moshemoshell answered 10/12, 2013 at 12:10 Comment(0)
F
1

While ExpectedException cannot be used as-is to verify the exception's message, you could implement your own exception validation logic by inheriting from ExpectedExceptionBaseAttribute:

By implementing your own expected exception verification. you can specify additional information and requirements that the built-in methods of the ExpectedExceptionAttribute class cannot handle, such as the following:

  • Verifying the state of the exception.
  • Expecting more than one type of exception.
  • Displaying a custom message when a wrong type of exception is thrown.
  • Controlling the outcome of a negative test.

In your case, it could look something like this:

public sealed class ExpectedExceptionMessageAttribute<T> : ExpectedExceptionBaseAttribute
{
    readonly string _expectedMessage;
    public ExpectedExceptionMessageAttribute(string expectedMessage)
    {
        _expectedMessage = expectedMessage;
    }

    protected override void Verify(System.Exception exception)
    {
        // Handle assertion exceptions from assertion failures in the test method
        base.RethrowIfAssertException(exception);

        Assert.IsInstanceOfType(exception, typeof(T), "wrong exception type");
        Assert.AreEqual(_expectedMessage, exception.Message, "wrong exception message");
    }
}

HAving said that, I would still be inclined to use the direct try-catch approach though as it is more specific in where exactly the exception is expected to be thrown:

public static void Throws<T>(Action action, Predicate<T> predicate = null) 
                    where T : Exception
{
    try
    {
        action();
    }
    catch (T e)
    {
        if (predicate == null || predicate(e))
        {
            return;
        }

        Assert.Fail($"Exception of type {typeof(T)} thrown as expected, but the provided predicate rejected it: {e}");
    }
    catch (Exception e)
    {
        Assert.Fail($"Expected exception of type {typeof(T)} but a different exception was thrown: {e}");
    }

    Assert.Fail($"No exception thrown, expected {typeof(T)}");
}
Flake answered 23/7, 2017 at 23:36 Comment(0)
S
0

You don't need an assertion if you're using ExpectedException attribute, in fact your code shouldn't be able to arrive at the assertion.

look: http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.expectedexceptionattribute.aspx

If you want to be sure the exception is thrown you should put an Assert.Fail() after the operation that should throw the exception, in this case if the exception is not thrown, the test will fail.

Sundog answered 10/12, 2013 at 12:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.