in

Platinum Bay

Peace, Love, Team System, and Community

This Blog

Syndication


.NETicated

Pop Quiz: .NET Integers, Unit Testing, and Boundary Checking

I ask this question in a bunch of my talks, mostly because most folks aren’t aware of this. What is the bug in the following method?

public int Add(int num1, int num2)
{
    return num1 + num2;
}

Do you see it? In a simple unit test, the method appears to work as expected:

[TestMethod()]
public void AddTest()
{
    MathHelper target = new MathHelper();
    int num1 = 16;
    int num2 = 16;
    int expected = 32;
    int actual = target.Add(num1, num2);
    Assert.AreEqual(expected, actual); // PASS
}

However, what if we pass in a different set of parameters, say int.MaxValue?

[TestMethod()]
public void AddMaxTest()
{
    MathHelper target = new MathHelper();
    int num1 = int.MaxValue;
    int num2 = int.MaxValue;
    int result = target.Add(num1, num2);

    Assert.Fail("Expected an overflow exception. Received: " + result);
}

Any guesses on the outcome of this test? In actuality, no exception is thrown. The test fails with the output: “Assert.Fail failed. Expected an overflow exception. Received: -2”. The output from the fail assert is “-2”. What!? Is it a bug in the .NET framework? What’s going on?

The answer lies in that I am passing in a signed int. In a signed int, the top bit is flag bit indicating positive or negative, leaving the other 31 bits to indicate the numeric value. When doing binary math that overflows the 31 bits, the 32nd bit is switched as though it is unsigned. In this case a positive becomes a negative and the result becomes –2. Let’s hope the system isn’t trying to deposit $100 into an account with $2,147,483,647.

But what does this mean to the original method? How do we handle this scenario? The point of this experiment isn’t to demonstrate a potential issue with the .NET framework. Rather, I’d like you to take notice of the first unit test. The test does evaluate the method for proper functioning, 100% code coverage would be achieved on the Add method, and yet the issue at hand is not found. And to this I would like to make an important point:

Code Coverage is a misleading metric.

In order to properly test your code, it is important to not only make sure you test as much as possible, but to ensure you also perform boundary checking. If the max values weren’t tested, it might not have been found that the code could erase $2,147,483,749 from some pour soul’s bank account. Well, he’d be poor after the fact. Are here is my second point:

Boundary check everything.

To help solve this problem, there is a neat tool from Microsoft Research called Pex. From the Pex website:

Right from the Visual Studio code editor, Pex finds interesting input-output values of your methods, which you can save as a small test suite with high code coverage. Pex performs a systematic analysis, hunting for boundary conditions, exceptions and assertion failures, which you can debug right away. Pex enables Parameterized Unit Testing, an extension of Unit Testing that reduces test maintenance costs.

What I would really love to see someday is a combination of existing code coverage in Visual Studio Team System with parameter boundary checking in Pex to give a truer sense of test coverage. Maybe for Dev11?

Published Aug 26 2009, 08:10 PM by Steve
Filed under: , , ,

Comments

August 27, 2009 5:25 AM

Pingback from  Dew Drop – August 27, 2009 | Alvin Ashcraft's Morning Dew

 

Leave a Comment

(required )  
(optional )
(required )  
Add

About Steve

Steve Andrews is a Team System MVP and INETA Speaker, and has been working as a developer for more than 9 years. During this time, he has designed and developed applications in such widely varying areas as trust accounting, medical information management, supply chain management, and retail systems. Steve is also an MCP, ICSOO, Speaker Liaison for the Philly .NET User Group, and community fanatic.
Powered by Community Server (Commercial Edition), by Telligent Systems
© Platinum Bay | Some Rights Reserved Creative Commons License

Disclaimer: The information in this weblog is provided "AS IS" with no warranties, and confers no rights. This weblog does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion. Feel free to challenge me, disagree with me, or tell me I'm completely nuts in the comments section of each blog entry, but I reserve the right to delete any comment for any reason whatsoever (abusive, profane, rude, or annonymous comments) - so keep it polite, please.