From JUnit to SpringUnit Tests

Class Under Test

Previous Next
We begin with our class under test, CompositeDate. CompositeDate is a simple-minded class that represents a date as a tuple consisting of a year, month and day of the month. Of course, it isn't intended for any production use, but it has some interesting properties for testing, because, as we know, there are many boundary conditions and constraints. CompositeDate imposes preconditions on its clients, namely, that months are integers in the range from 1 to 12, inclusive, and days are integers from 1 to 31. There are many combinations of year, month and day that are invalid, but that satisfy these preconditions. CompositeDate checks for these cases and throws an InvalidDateException whenever these are detected. The task of testing a class like this quickly turns to the identification of boundary and special cases, and then proving that these are all handled correctly. CompositeDate includes three types of state-changing methods that require testing: the constructor, field setters, and field incrementers and decrementers. For the purpose of this exercise, only tests of the constructor will be shown; it should be obvious to the reader that the patterns of test design would apply equally to tests of the other methods. Here is an excerpt from our class under test, CompositeDate.
package org.springunit.examples;

public class CompositeDate implements Serializable {

    /**
     * Create CompositeDate having day, month and year.
     * @Pre("1 <= day && day <= 31")
     * @Pre("1 <= month && month <= 12")
     * @throws InvalidDateException if day, month and year do
     * not specify a valid date
     */
    public CompositeDate(int year, int month, int day) throws InvalidDateException {
        assert 1 <= day && day <= 31 : "1 <= day && day <= 31";
        assert 1 <= month && month <= 12 : "1 <= month && month <= 12";
        this.day = day;
        this.month = month;
        this.year = year;
        validateDate(year, month, day);
    }
	
    public static boolean isValidDate(int year, int month, int day) {
        return isValidLeapDay(year, month, day) || isValidMonthAndDay(month, day);
    }
	
    public static boolean isValidLeapDay(int year, int month, int day) {
        return (day != 29 || month != 2) || ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0));
    }

    public static boolean isValidMonthAndDay(int month, int day) {
        assert 1 <= month && month <= 12 : "1 <= month && month <= 12";
        assert 1 <= day && day <= 31 : "1 <= day && day <= 31";
        return !((day > 29 && month == 2) || (day > 30 && (month == 4 || month == 6 || month == 9 || month == 11)));
    }

    protected static void validateDate(int year, int month, int day) throws InvalidDateException {
        validateLeapDay(year, month, day);
        validateMonthAndDay(month, day);
    }
	
    protected static void validateLeapDay(int year, int month, int day) throws InvalidDateException {
        if (!isValidLeapDay(year, month, day)) {
            throw new InvalidDateException("February 29 is not valid for the year " + year);
        }
    }

    protected static void validateMonthAndDay(int month, int day) throws InvalidDateException {
        if (!isValidMonthAndDay(month, day)) {
            throw new InvalidDateException(day + " is not valid for the month " + month);
        }
    }

    private int day;
    private int month;
    private int year;
	
}
Previous Next