TestingFunctionsExercises

From GIS CS4
Jump to: navigation, search

Contents

Basic Testing

A very important aspect of programming is testing!

You have been asked to write test functions for each of the function exercises.

This can be approached in different ways.

It is important to choose your test data carefully so that all unusual cases are tested e.g. 0, -ve, large numbers, etc.

We will look at some example test code based on exercise 1: =

Example Code for Ex 1.

/*
 Exercise 1. Write a JavaScript function '''isEven''' 
 that takes as input the parameter '''zInt''' (an integer) 
 and returns '''true''' if number is even, and returns '''false''' if number is odd.
 */
var isEven = function(zInt)
{
    return ((zInt % 2) === 0);
};

Example Test Function for Ex 1. Using Text Output

First we will write a function that displays the results of calling the isEven function with the given test data:

// A function to generate a text string to describe the result of the isEven function
var getIsEvenText = function(zInt)
{
    if (isEven(zInt))
    {
        return("The number: " + zInt + " is even");
    }
    else
    {
        return("The number: " + zInt + " is odd");
    }
};

We can then call the above function with different test data:

// A function to generate a text string to describe the result of the function call
var testIsEven= function()
{
    var y=0;
    text(getIsEvenText(2), 50, y+=50);  // Test case 2 should be even
    text(getIsEvenText(3), 50, y+=50);  // Test case 3 should be odd
    text(getIsEvenText(0), 50, y+=50);  // Test case 0 should be even
    text(getIsEvenText(-6), 50, y+=50); // Test case -6 should be even
    text(getIsEvenText(-5), 50, y+=50); // Test case -5 should be odd
};

Finally we can invoke the test function:

// A function to generate a text string to describe the result of the function call
testIsEven();

Regression Testing

Regression testing is the ability to test, and retest code whenever the code is modified.

If you are developing a larger piece of software, it is highly beneficial if testing is automatic and repeatable.

Automatic testing

An automatic test requires minimal human intervention.

In the example test function above we displayed text to describe the outcome of calling a function with given test input data.

This requires a human to read the text output and decide whether the function has performed correctly or not.

In an automatic test, the program itself is able to determine whether a test has passed or failed, and finally report the result to the tester.

Repeatable testing

A program may be modified, either to fix bugs, or else to extend it's functionality.

The modified software needs to be tested. Additional tests need to be added to check the new features, and the original features need to be retested to check that nothing has been broken.

Example Test Function for Ex 1. Using Automatic Reporting

We can write an automatic test function that calls our function with different parameter values.

If all cases run successfully, then the auto test function should return true.

If a given case fails, then the auto test function will return false.

Additional test cases can easily be added.

If an error is found, we need to investigate to discover which case has failed and why.

// A function to test different use cases of the function isEven
var autotestIsEven = function()
{
    // test even numbers
    if (!isEven(2))   {return false;}  // Test case 2 should be even 
    if (!isEven(0))   {return false;}  // Test case 0 should be even
    if (!isEven(-6))  {return false;}  // Test case -6 should be even

    // test odd  numbers
    if (isEven(3))    {return false;}  // Test case 3 should be odd
    if (isEven(-5))   {return false;}  // Test case -5 should be odd

    return true;    // no problems - all tests ran successfully
};

We can invoke the auto test function:

if (!autotestIsEven())
{
    // Something went wrong! - do something about it!
    text("isEven function *** ERROR! ***", 50, 50);
}

Example Test Function for Ex 3. Using Automatic Reporting

Here is a similar example auto test function for Ex 3. isLeapYear:

if year is divisible by 400 then is_leap_year
else if year is divisible by 100 then not_leap_year
else if year is divisible by 4 then is_leap_year
else not_leap_year

// A function to test different use cases of the function isLeapYear
var autotestIsLeapYear = function()
{
    // test leapyears (should return true)
    if (!isLeapYear(400))    {return false;}
    if (!isLeapYear(1600))   {return false;}
    if (!isLeapYear(104))    {return false;}
    if (!isLeapYear(120))    {return false;}
    if (!isLeapYear(4))      {return false;}
    if (!isLeapYear(60))     {return false;}
    if (!isLeapYear(208))    {return false;}
    if (!isLeapYear(516))    {return false;}

    // test non-leapyears (should return false)
    if (isLeapYear(200))     {return false;}
    if (isLeapYear(500))     {return false;}
    if (isLeapYear(3))       {return false;}
    if (isLeapYear(77))      {return false;}

    return true;    // no problems - all tests ran successfully
};

We can invoke the auto test function:

if (!autotestIsLeapYear ())
{
    // Something went wrong! - do something about it!
    text("isLeapYear function *** ERROR! ***", 50, 50);
}

Master Test Function Using Automatic Reporting

We can write a master test function that will invoke each of our auto test functions and return the overall result:

var masterAutoTest = function()
{
    if (!autotestIsEven())         {return false;}
    if (!autotestIsLeapYear())     {return false;}
    // include auto test function for each exercise ...

    return true;    // hooray! - no problems found (yet!)
};

if (!masterAutoTest())
{
    // Something went wrong! - do something about it!
}

Debugging When Errors Occur

If an error does occur, we can use different techniques to find out more.

Binary Chop

One method is to a set break-point half way through the code (i.e. half way through the master test function).

If the break-point is reached, this means that the error does not occur until after the break-point (otherwise the test would have returned an error already).

If the break-point is not reached, this means that the error occurs before the break-point (otherwise the test would not yet have returned an error).

We then keep setting break-points at the halfway point of the area that we have confined the error has occurred in.

Eventually we will home in on the exact test that caused an error and we can debug that specific case of the function call.

Using Error Codes

A more sophisticated method is to define individual error codes for each case.

If you are interested in more detail, see here: Using Error Codes

Personal tools
Namespaces

Variants
Actions
Navigation
Tools