Week 03-1: Unit Testing / Developing a Sort

Sorting an Array

Let’s go through a workflow of development with a program that sorts words.

The Problem

Print out the command-line arguments in lexicographic order:

% java sort the quick brown fox jumped over the lazy dog
brown dog fox jumped lazy over quick the the

The Plan

public class Sort {
    /** Sort lexicographically */
    public static void main(String[] words) {
        sort(words, 0, words.length - 1);
        print(words);
    }

    static void sort(String[] A, int L, int U) { /* "TOMORROW" */ }

    static void print(String[] A) {}
}

How do we know that it works?

  • Unit testing - testing of individual units (methods) within a program, rather than the whole program.

  • Module testing - Testing of classes or other groupings of methods and data.

  • System testing - Testing of a program’s entire functionality.

  • Integration testing - Tests that modules work correctly together

  • Regression testing - Ensures that fixes, enhancements, or other changes have not introduced faults (regressions)

We will mainly be using the JUnit tool for unit testing

Test-Driven Development

A popular development practice, Test-Driven Development (or TDD), involves writing the tests first, then implementing your logic to pass the tests.

  • Implement one unit at a time, run the tests, fix and refactor until it works.

  • This is only lightly going to be pushed in this course, but it is really good practice for real-world programming.

Let’s test our sort program

  • Pretty easy: Give a bunch of arrays to sort, then make sure they are each sorted properly.

  • We must make sure that we cover all cases:

    • Corner (edge) cases: empty arrays, one element, all elements the same, etc.

    • Representative (middle) cases: elements reversed, elements in order, one pair of elements reversed

Coverage is a measure of how much of your program is actually being tested. You should strive to get as much coverage as you can in your code. If using a TDD approach, you would almost always be near 100% coverage.

JUnit

  • We use the @Test annotation on a method, which tells JUnit to use that method as a test call. This method would contain assertions, which perform the validations of your program’s output.

An example of an assertion would be similar to the following:

assertArrayEquals("Empty array failed", 
                  new String[] {}, 
                  runSort(new String[] { }, 0, -1));