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
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.
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With