GOTCHA 8 Division operation isn t consistent between types


GOTCHA #8 Division operation isn't consistent between types

When 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.

Unit Testing with NUnit

Unit testing is gaining strong acceptance in the .NET community. NUnit is an open source tool that allows you to automate and exercise your test cases. For a good discussion of Test-Driven Development refer to [Beck03]. You can find discussions specific to .NET in [Jeffries04, Newkirk04]. You can learn how to use NUnit from [Hamilton04, Hunt03].


Example 1-16. NUnit test to assert DivisionByZeroException

C# (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-16


The 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 zero

C# (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 NUTSHELL

If 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 ALSO

Gotcha #29, "Unit testing private methods is tricky."



    .NET Gotachas
    .NET Gotachas
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 126

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net