[ExpectedException(typeof(AnExceptionBaseException))]

3

I wrote a unit test in such a way that it should throw AnException or AnotherException, both deriving from AnExceptionBaseException. I then proceeded to add an ExpectedExceptionAttribute for the base exception, only to find that my test will still be marked as failed.

Test Name: Call_Should_Throw_If_Device_Is_Not_Ready Test

...

Result Message: Test method DiskManagementTests.DiskFreeSpaceTests.Call_Should_Throw_If_Device_Is_Not_Ready threw exception System.IO.FileNotFoundException, but exception System.IO.IOException was expected. Exception message: System.IO.FileNotFoundException: The device is not ready. (Exception from HRESULT: 0x80070015)

This seems like a reasonable design decision because, in this particular case, the exception is generated from an HRESULT return code. That makes it nearly impossible to determine which exception will be thrown. At least not without copying the code logic from the unit that my test is supposed to ...test.

My code (I believe this can throw either FileNotFound or DirectoryNotFound):

[TestMethod]
[ExpectedException(typeof(IOException))]
public void Call_Should_Throw_If_Device_Is_Not_Ready()
{
    foreach (DriveInfo drive in DriveInfo.GetDrives().Where(drive => !drive.IsReady))
    {
        DiskFreeSpace diskFreeSpace = DiskManagement.GetDiskFreeSpace(drive.RootDirectory.FullName);
        Assert.Fail("API call did not fail even though the drive reports that it is not ready.");
    }
    Assert.Inconclusive("All drives were ready. Try testing with an empty disc drive.");
}

Do I need to reconsider the way I write unit tests?

EDIT

This scenario is supported after all. All it really took was setting AllowDerivedTypes to true.

[TestMethod]
[ExpectedException(typeof(IOException), AllowDerivedTypes = true)]
public void Call_Should_Throw_If_Device_Is_Not_Ready()
{
    // ...
}
c#
mstest
asked on Stack Overflow Jul 17, 2013 by Steven Liekens • edited Jul 17, 2013 by Steven Liekens

1 Answer

1

You can create your own ExpectedException attribute that will check if the thrown exception inherites the Exception defined in the attribute.

public sealed class MyExpectedException : ExpectedExceptionBaseAttribute
{
    private Type _expectedExceptionBaseType;

    public MyExpectedException(Type expectedExceptionType)
    {
        _expectedExceptionBaseType = expectedExceptionType;
    }

    protected override void Verify(Exception exception)
    {
        Assert.IsNotNull(exception);
        Assert.IsTrue(exception.GetType().IsInstanceOfType(typeof(_expectedExceptionBaseType)) || 
                      exception.GetType().IsSubclassOf(typeof(_expectedExceptionBaseType)));
    }
}

and change the attribute to your test:

[MyExpectedException(typeof(IOException))]
answered on Stack Overflow Jul 17, 2013 by chaliasos • edited Jul 17, 2013 by chaliasos

User contributions licensed under CC BY-SA 3.0