GOTCHA #8 Division operation isn't consistent between typesWhen you divide by zero, you expect a DivisionByZeroException to be thrown. While this does happen for integer division, floating point division does not cause this exception. Consider Example 1-16, where I use an NUnit test to assert for division by zero.
Example 1-16. NUnit test to assert DivisionByZeroExceptionC# (DivByZero) //Calculator.cs using System; namespace DivisionByZeroExample { public class Calculator { public int Divide(int operand1, int operand2) { return operand1 / operand2; } } } //Test.cs using System; using NUnit.Framework; namespace DivisionByZeroExample { [TestFixture] public class Test { private Calculator calc; [SetUp] public void Setup() { calc = new Calculator(); } [Test] public void TestSimpleDivide() { Assert.AreEqual(2, calc.Divide(4, 2)); } [Test, ExpectedException(typeof(DivideByZeroException))] public void TestDivisionByZero() { calc.Divide(4, 0); } } } VB.NET (DivByZero) 'Calculator.vb Public Class Calculator Public Function Divide(ByVal operand1 As Integer, _ ByVal operand2 As Integer) As Integer Return operand1 \ operand2 End Function End Class 'Test.vb Imports NUnit.Framework <TestFixture()> _ Public Class Test Private calc As Calculator <SetUp()> _ Public Sub Setup() calc = New Calculator End Sub <Test()> _ Public Sub TestSimpleDivide() Assert.AreEqual(2, calc.Divide(4, 2)) End Sub <Test(), ExpectedException(GetType(DivideByZeroException))> _ Public Sub TestDivisionByZero() calc.Divide(4, 0) End Sub End Class The Divide() method divides its first parameter by its second one. There are two test cases. The first one invokes Divide() with parameters 4 and 2; the second calls it with the values 4 and 0. When the code in Example 1-16 is executed in NUnit, both the test cases succeed as shown in Figure 1-11. Figure 1-11. NUnit GUI output for code in Example 1-16The TestDivisionByZero test case has declared the ExpectedException attribute, and announced that it expects a DivisionByZeroException. This test succeeds since the Divide() method does indeed throw a DivisionByZeroException. Now, if the Divide() method performs floating-point division instead of integer division, the result will be different. Let's change the Divide() method of the Calculator class to use double instead of int (Integer in VB.NET), as shown in Example 1-17. Example 1-17. Example of floating point division by zeroC# (DivByZero) public double Divide(double operand1, double operand2) { return operand1 / operand2; } VB.NET (DivByZero) Public Function Divide(ByVal operand1 As Double, _ ByVal operand2 As Double) As Double Return operand1 / operand2 End Function The effect of the code change in Example 1-17 can be seen in the NUnit GUI shown in Figure 1-12. Note that the TestDivisionByZero test case fails because the DivisionByZeroException is not thrown. What is the result then? If either of the operands is a System.Double or System.Single, then the operation appears to succeed; no exception is thrown. But the result is an invalid number defined as either Double.PositiveInfinity or Double.NegativeInfinity, depending on the signs of the operands. However, you cannot do a simple comparison to test this; you must call Double.IsInfinity(). Floating-point operations do not throw exceptions. Figure 1-12. Failure to throw DivisionByZeroException(If the operands are Single instead of Double, the appropriate values are Single.PositiveInfinity and Single.NegativeInfinity. Single also offers the IsInfinity() method.) IN A NUTSHELLIf dealing with integer division, expect a DivisionByZeroException. Otherwise, check the result by calling the IsInfinity() method of System.Double or System.Single as appropriate. Remember that floating-point operations don't throw exceptions. You can avoid problems like this by checking the denominator before you perform the operation. SEE ALSOGotcha #29, "Unit testing private methods is tricky." |