SpringUnit Tutorial

Example 1

Previous Next
In the first example, we will write a SpringUnit test that shows the behavior of the setDay method for valid inputs at the boundaries. The algorithm of the test is simple. For the first case, we will create a CompositeDate for a day in the middle of January and then set the day to the 1st. In the second case, we will create a date in December and set the day to the 31st. Here is the skeleton of the first example.
package org.springunit.examples.tutorial;

import org.springunit.examples.CompositeDate;
import org.springunit.framework.SpringUnitTest;

public class CompositeDateTutorialExample1Test extends SpringUnitTest {
	
    public void testJan01() throws Exception {
        runSetDay();
    }
	
    public void testDec31() throws Exception {
        runSetDay();
    }

    protected void runSetDay() throws Exception {
        CompositeDate subject = getObject("subject");
        int day = getObject("day");
        int expectedDay = getObject("expectedDay");
        subject.setDay(day);
        assertEquals(expectedDay, subject.getDay());
    }
    
    // properties still to be added
	
}
The test class, CompositeDateTutorialExample1Test, extends the SpringUnit class, org.springunit.framework.SpringUnitTest. There are two tests, testJan01 and testDec31; each of these calls the method runSetDay, which implements the test algorithm common to both. The algorithm is straightforward: it creates an instance of the class under test; sets the value of the day to be used as an argument to the method call to be tested; sets the value of the expected result; calls the setDay method; and finally, compares the expected and actual results. Implicitly, this algorithm checks that no exception has been thrown. The first thing to notice is the getObject(String) method, called in the first three lines of runSetDay. This method is inherited from SpringUnitTest. It retrieves named values from a data structure to be described later. There is nothing special about the last two lines, which are just normal JUnit programming As you will see later, there are a few naming conventions in SpringUnit that must be observed. However, in this case, the name of the method called by the tests, runSetDay, is completely your choice. (Actually, you can choose any name that doesn't begin with "test", which, as you know, has special meaning inside the JUnit framework.) This test is not yet ready to run. First, we must create and configure test data as shown next.
package org.springunit.examples.tutorial;

public class CompositeDateTutorialExample1Test extends SpringUnitTest {

    // Test methods omitted
    
    public SpringUnitContext getCompositeDateTutorialExample1Test() {
        return this.compositeDateTutorialExample1Test;
    }

    public void setCompositeDateTutorialExample1Test(
            SpringUnitContext compositeDateTutorialExample1Test) {
        this.compositeDateTutorialExample1Test = compositeDateTutorialExample1Test;
    }
	
    private SpringUnitContext compositeDateTutorialExample1Test;

}	
Here you will see that we have introduced a new property of type SpringUnitContext. In a moment, we'll examine the structure of a SpringUnitContext. First, we note the first naming convention that we have encountered with SpringUnit: the name of the SpringUnitContext property must be the same as the simple name of the class. Later in the tutorial, we will see examples of SpringUnitTests that use inheritance. This requirement holds for every abstract and concrete subclass of a SpringUnitTest. The code for this first example is actually done. The next step is to create a Spring bean configuration file that will hold the data inputs and expected values.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>

    <bean id="compositeDateTutorialExample1Test" class="org.springunit.framework.SpringUnitContext">
        <property name="data">
            <map>
                <!-- Test data values go here -->
            </map>
        </property>
    </bean>
	
</beans>
This file begins with some boilerplate that references the spring-beans.dtd and declares one bean. That bean is a SpringUnitContext, and its name, "compositeDateTutorialExample1Test", corresponds with the name of the property that we just added to the test. This demonstrates the second naming convention that must be observed: the name of the SpringUnitContext bean declared in the XML configuration file must match the name of the property in the SpringUnitTest, which, as we have seen, is the same as the simple name of the test class. This XML file itself is named CompositeDateTutorialExample1Test.xml and illustrates the third naming convention: the name of the Spring bean configuration file must be identical to the simple name of the test class, appended by ".xml". This file must be located on the classpath in the same package as the Java class. For example, if the fully qualified name of the test class is com.foo.bar.MyTest, then a file named MyTest.xml must be located in on the classpath in com/foo/bar/. Earlier versions of SpringUnit expected to find this file in the default package at the root of the classpath. This is supported for backward-compatibility but is now discouraged. A SpringUnitContext is a bean with one property, called "data". This property is a map that holds all of the test data values as shown next.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>

    <bean id="compositeDateTutorialExample1Test" class="org.springunit.framework.SpringUnitContext">
        <property name="data">
            <map>
                <entry key="testJan01">
                    <map>
                        <entry key="subject">
                            <bean class="org.springunit.examples.CompositeDate">
                                <constructor-arg><value type="int">2006</value></constructor-arg>
                                <constructor-arg><value type="int">1</value></constructor-arg>
                                <constructor-arg><value type="int">15</value></constructor-arg>
                            </bean>
                        </entry>
                        <entry key="day">
                            <value type="int">1</value>
                        </entry>
                        <entry key="expectedDay">
                            <value type="int">1</value>
                        </entry>
                    </map>
                </entry>
                <entry key="testDec31">
                    <map>
                        <entry key="subject">
                            <bean class="org.springunit.examples.CompositeDate">
                                <constructor-arg><value type="int">2006</value></constructor-arg>
                                <constructor-arg><value type="int">12</value></constructor-arg>
                                <constructor-arg><value type="int">15</value></constructor-arg>
                            </bean>
                        </entry>
                        <entry key="day">
                            <value type="int">31</value>
                        </entry>
                        <entry key="expectedDay">
                            <value type="int">31</value>
                        </entry>
                    </map>
                </entry>
            </map>
        </property>
    </bean>
	
</beans>

The map named "data" itself contains maps, each of whose key is the name of a test. This leads to the fourth convention: for every test method in the test class, there exists an entry in the data map whose key is the name of the test and whose value is a map. (Later, in Example 6, we will see that the data map can contain an element whose is are not the name as the name of a test.) So far, our test has two methods, so the data map contains two entries, identified by "testJan01" and "testDec31". Notice that each test forms something of a namespace, so that the same object name (e.g. "day") refers to a distinct object as each test is executed.

Now it is plain how our two boundary cases for the setDay method will be tested. In the first test, we start with the date of January 15 and change it to January 1; in the second, we begin with December 15 and change to December 31. Again, making sure that the Spring bean XML file has been correctly named and can be found on the classpath, you should be able to execute this test and see it pass.

Previous Next