tags:

views:

212

answers:

5

What is the best way of testing a function that throws on failure? Or testing a function that is fairly immune to failure?

For instance; I have a I/O Completion Port class that throws in the constructor if it can't initialise the port correctly. This uses the Win32 function of CreateIoCompletionPort in the initialiser list. If the handle isn't set correctly - a non-null value - then the constructor will throw an exception. I have never seen this function fail.

I am pretty certain that this (and other functions like it in my code) if they fail will behave correctly, the code is 50 lines long including white-space, so my questions are

a) is it worth testing that it will throw
b) and if it is worth testing, how to?
c) should simple wrapper classes as these be unit-tested?

For b) I thought about overriding CreateIoCompletionPort and passing the values through. In the unit test override it and cause it to return 0 when a certain value is passed in. However since this is used in the constructor then this needs to be static. Does this seem valid or not?

Thanks, G.

+1  A: 

Can you set a breakpoint in the constructor and force it to fail manually? I realise it isn't going to help you out with unit tests, but at least you'll get an idea of how your code behaves upon failure.

ZombieSheep
+2  A: 

It is definitely worthwhile to test failure conditions, both that your class properly throws an exception when you want it to and that exceptions are handled properly in the class.

This can easily be done if you are acting on an object passed in to the constructor... just pass in a mock. If not, I tend to prefer to have the functionality moved to a protected method, and override the protected method to evoke my failure case. I will use Java as an example, but it should be easy enough to port the ideas to a C# case:

public class MyClass {
    public MyClass() throws MyClassException {
        // Whatever, including a call to invokeCreateIoCompletionPort
    }

    protected int invokeCreateIoCompletionPort(String str, int i) {
        return StaticClass.createIoCompletionPort(str, i);
    }
}

public class MyTest {
    public void myTest() {
        try {
            new MyClass();
            fail("MyClassException was not thrown!");
        } catch (MyClassException e) {
        }
    }

    private static class MyClassWrapper extends MyClass {
        @Override
        protected int invokeCreateIoCompletionPort(String str, int i) {
            throw new ExpectedException();
        }
    }
}

As you can see, it is pretty easy to test whether an exception is being thrown by the constructor or method you are testing, and it is also pretty easy to inject an exception from an external class that can throw an exception. Sorry I'm not using your actual method, I just used the name to illustrate how it sounded like you are using it, and how I would test the cases it sounded you wanted to test.

Basically, any API details you expose can usually be tested, and if you want to KNOW that exceptional cases work as they should, you probably will want to test it.

Mike Stone
A: 

@ZombieSheep: I can and it does.

I've added a c) to my original question.

graham.reeds
+1  A: 

You should consider writing your code in such a way that you can mock your I/O completion port. Make an interface/abstract class that exposes the methods you need on the I/O object, and write and test implementation that does things like it's supposed to (and an option to simulate failure perhaps).

AFAIK it's a common practice to mock external resources when unit testing, to minimize dependencies.

Erik van Brakel
+3  A: 

If you are doing this in .NET, there is an ExpectedException attribute that you can add to your test:

[Test, ExpectedException(typeof(SpecificException), "Exception's specific message")]
public void TestWhichHasException()
{
    CallMethodThatThrowsSpecificException();
}

Test will pass if the exception of that type and with the specified message is thrown. The attribute has other overloads including having InnerExceptions, etc.

Jon Limjap