Test Values

When you are testing a piece of code then it is important that you select the correct test cases. To help to explain this more simply let's look at an actual example.

The following toInt() function tests if the string passed to it can be converted to an integer. If it can be converted then the string is converted to a number and is returned. If the string can't be converted to an integer then the special JavaScript value NaN is returned.

var toInt = function(x) {
var n = (/^(-?\d+)$/.exec(x));
return (n!==null)? +n[1] : NaN;

Testing obvious values such as '3' and '06' return the expected results and so we know that the function works for the most obvious values. It is the not so obvious values that we need to concentrate on for most of our tests.

One thing that makes it particularly easy to select good test cases for this function is that it almost replicates part of the functionality of the built in parseInt() and Math.floor() functions. This means that we can get some good test cases by considering the situations where one of those two functions is expected to return a different value from our function.

One thing to consider with parseInt() is that it's primary purpose is to convert from different number bases to base 10. The function takes an optional second parameter that identifies the starting number base which can be anything between 2 and 36. The only value that the second parameter can have where it isn't converting number bases is 10. So the potential test cases for our toInt() function from parseInt() will have the second parameter either set to 10 or omitted.

If the second parameter of parseInt() is omitted then most but not all values in the first parameter will be considered to be decimal. Those exceptions will be where the value contains a prefix that identifies the number base. This gives us our first test case - 'x0f'. This value is a valid integer as far as parseInt() is concerned as it is considered to be a hexadecimal number and converts to 15. It is not a valid integer as far as our toInt() function is concerned.

Even with 10 in the second parameter of the parseInt() there are values that it will convert to integers that are not integers. The parseInt() function truncates the input as soon as an invalid character is found and so '1x' will be converted to 1 - '1x' is not however an integer and so our toInt() function again differs in the result.

Math.floor() suffers neither of these problems and will achieve the same result as our toInt() function for both of those test cases. There are some situations where Math.floor() will return the same result as parseInt() where the value is still not an integer. One such example is '5.5'. The parseInt() truncates the value at the '.' as that is never part of an integer. The Math.floor() converts the '5.5' to a number and then rounds it down to the nearest integer. In both cases they return 5 however the original value still isn't an integer and so the result from our toInt() is different.

An example of where parseInt() and Math.floor() give different answers is with negative numbers - eg. '-5.5' - where parseInt() will truncate that to -5 and Math.floor() will round it down to -6. Either way it still isn't an integer and so our toInt() provides the same NaN as in the prior test cases.

At this point we have tested four different types of input where parseInt() and/or Math.floor() provide an integer answer from something that isn't an integer. That the function is able to distinguish these situations is evidence of the usefulness of our toInt() function as it is not a direct replacement for either of the built in functions. That our function correctly returns NaN in each of these cases shows that the function is working correctly and is not simply being used as a wrapper around one of the other two functions.

Now we need some test cases where the value might be an integer. One area where we always need to test are boundary conditions. What will happen if the number passed to our toInt() is bigger than the maximum integer that JavaScript can store as an integer. If we take '10000000000000001' as a test case then we find that the function returns 10000000000000000 which is actually one less than the integer we gave it. All of the code in our function is working right up until the +n[1] which finds that our integer is now too big to store as an integer and so it gets stored as a floating point number where the value is only accurate to around fifteen to sixteen digits. At this point we need to decide whether this is an acceptable way for our function to handle really big integers or whether we need to amend the function to return a different value if the value is too big to store as an exact integer.


This article written by Stephen Chapman, Felgall Pty Ltd.

go to top

FaceBook Follow
Twitter Follow