views:

136

answers:

4

I have come to something of a crossroads. I recently wrote a 10,000 line application with no TDD (a mistake I know). I definitely ran into a very large amount of errors but now I want to retrofit the project. Here is the problem I ran into though. Lets take a example of a function that does division:

public int divide (int var1, int var2){
if (var1 == 0 || var2 == 0)
   throw new RuntimeException("One of the parameters is zero");
return var1 / var2;
}

In this situation I'm throwing a runtime error so that I can fail and at least find out that my code is broke somewhere. The question is 2 fold. First, am I making the correct use of the exceptions here? Secondly how do I write a test to work with this exception? Obviously I want it to pass the test but in this case it's going to throw an exception. Not too sure how one would work that out. Is there a different way that this is generally handled with TDD?

Thanks

+3  A: 

To answer your first question:

If it's quite likely the denominator argument to divide will be 0 then you shouldn't be using exception handling to trap the error. Exceptions are expensive and shouldn't be used to control program flow. So you should still check, but return an error code (or use a nullable type as the return value) and your calling code should check on this and handle it appropriately.

public int? divide (int var1, int var2)
{
    if (var2 == 0)
    {
        return null;  // Calling method must check for this
    }
    return var1 / var2;
}

If zeros are truly the exception - e.g. there should be no way that they can be passed - then do as you do now.

To answer your second question:

In your test methods that check the failure code you need an exception handler:

try
{
    divide (1, 0);
    // If it gets here the test failed
}
catch (RuntimeException ex)
{
    // If it gets here the test passed
}
ChrisF
Hmm good answer, thank you. As pertains to question 1, is it always better to make the calling function validate the input before sending? Maybe that would be necessary no matter what. Hmm...
John Baker
@John - it's better to put all your validation in the same place, that way if your requirements change or you can now handle new inputs you only have to modify the code in one place rather than everywhere the low level function is called.
ChrisF
@Chris Hmm okay. That's a tough job I think, I need to do some research on how to accomplish that. Great point though. Thanks for the help
John Baker
Since the divide operator is not defined for a zero denominator, it makes perfect sense to forbid it. Allowing a zero denominator and then requiring the calling code to check that the result is "undefined" just complicates things. If the calling code is aware of undefined operations anyway, then it should not perform them.
Wim Coenen
I would tend to disagree with your comment re: division by zero returning an error code. A division by zero IS an exceptional circumstance. If you want to do a check on the denominator, put it in before the call to the division happens. The .NET framework, for instance, has a specific exception for this, called DivideByZeroException.
Mathias
+6  A: 

First, your first argument (the numerator) being zero probably shouldn't cause an exception to be thrown. The answer should just be zero. Only throw an exception when a user tries to divide by zero.

Second, there are two ways (using JUnit) to test that exceptions are thrown when they should be. The first "classic" method:

@Test
public void testForExpectedExceptionWithTryCatch()
        throws Exception {
    try {
        divide (1, 0);
        fail("division by zero should throw an exception!");
    } catch (RuntimeException expected) {
        // this is exactly what you expect so 
        // just ignore it and let the test pass
    }
}

The newer method in JUnit 4 uses annotations to cut down on the amount of code you need to write:

@Test(expected = RuntimeException.class)
public void testForExpectedExceptionWithAnnotation()
        throws Exception {
    divide (1, 0);
}

Here, because we added (expected = RuntimeException.class) to the annotation, the test will fail if the call to divide doesn't throw a RuntimeException.

Bill the Lizard
A: 

I am not answering your main question.

I would suggest using ArgumentException instead of RuntimeException.

EDIT: I am assuming .net :)

shahkalpesh
I would even go as far as suggesting DivideByZeroException :)
Mathias
A: 

Your question was language-agnostic, so my answer might not apply, but NUnit in .NET (and I believe JUnit too) have a specific notation for testing exceptions. In NUnit, your test would look like this:

[Test]
[ExpectedException(typeof(RuntimeException))]
public void DivideByZeroShouldThrow()
{
   divide(1,0);
}

The test will fail if the right type of exception is not thrown during the execution.
The try/catch approach works too, and has its advantages (you can pinpoint exactly where you expect the exception to occur), but it can end up being pretty tedious to write.

Mathias