Home > Software design >  How to test Assert for base class exception implementation using Microsoft Unit testing framework?
How to test Assert for base class exception implementation using Microsoft Unit testing framework?

Time:08-16

Here is specific case. I want to test this Assert.ThrowsException<DbException>(() => { MyMethod(0, 100); });

The problem is that exception thrown is SqlException. Why do I want to test base exception? Because I want a unified test for any of my 3 DB providers. The exception sometimes is OracleException or MySqlException. All 3 providers exceptions derive from DbException

Is there a way to test it nicely, using the Microsoft Unit Test framework?

CodePudding user response:

According to the documentation for Assert.ThrowsException this is expected. However, if you're able to use Fluent Assertions, this is in fact very easy to achieve.

Action action = () => MyMethod(0, 100);
action.Should().Throw<DbException>(); // add some more checks

// this would mimic the behavior of Assert.ThrowsException, which should fail.
action.Should().ThrowExactly<DbException>();

See also the tips on improving assertions under Tips/Exceptions.

The alternative would be to use regular try...catch like in the example below. You need to make sure that you capture all the code path' and don't accidentally succeed:

    /// <summary>
    /// Catching a base exception class just by using <see cref="Assert"/>.
    /// Do not use <see cref="ExpectedExceptionAttribute"/>, since it doesn't
    /// provide any type of validation.
    /// </summary>
    [TestMethod]
    public void CatchAderivedExceptionTheAssertWay()
    {
        try
        {
            // A test method that throws an exception.
            Action action = () => throw new ArgumentNullException("param1");
            action();
        }
        catch (ArgumentException e)
        {
            // This will catch any exception derived from ArgumentException.
            // Do some validation to ensure the right thing is caught,
            // like checking the parameter name.
            if (!e.ParamName.Equals("param1", StringComparison.Ordinal))
            {
                Assert.Fail("Reason why the validation failed.");
            }

            // Otherwise jump out of the test.
            return;
        }

        Assert.Fail("Make sure the test fails, in case the code inside try doesn't throw at all.");
    }

For completeness sake, there's also the ExpectedException attribute that can be added to a [TestMethod]. Due to the lack of validation options I would not recommend using it.

I'll add this question to my list of interview questions. Such a nice example.

CodePudding user response:

Thanks for all the leads, one from @StephanAdler

Considering limitations of given testing framework my sensible solution was this

Exception retEx = null;

try
{
    MyMethod(0, 100);;
}
catch (Exception ex)
{
    retEx = ex;
}

Assert.IsNotNull(retEx);
Assert.IsInstanceOfType(retEx, typeof(DbException));

Assert.IsInstanceOfType works perfectly with the base type

  • Related