Naked Objects
By Richard Pawson and Robert Matthews

Writing tests

Unit tests

To create a view-based unit test you must subclass the org.nakedobjects.testing.NakedTestCase class rather than the usual junit.framework.TestCase. To set up the simulated application, the classes that are to be used must be registered by calling the registerClass method.

The following code is taken from the unit test code from the ECS example. It shows how the test is set up and initialized. The call to the init method inside the main method sets up the Naked Objects framework to work locally:

package ecs.tests;

import junit.framework.TestSuite;
import junit.textui.TestRunner;
import org.nakedobjects.testing.NakedTestCase;
import org.nakedobjects.testing.View;
import ecs.delivery.*;

public class ECSUnitTests extends NakedTestCase {

    public static void main(java.lang.String[] args) {
        init();
        TestRunner.run(new TestSuite(ECSUnitTests.class));
    }

    public ECSUnitTests(String name) {
        super(name);
    }

    protected void setUp() {
        registerClass(Booking.class);
        registerClass(City.class);
        registerClass(Customer.class);
        registerClass(Location.class);
        registerClass(CreditCard.class);
    }
}

As when using Junit, each test should be written as a public method with the method name prefixed by 'test' and should make use of the mock views to simplify coding. The following example, taken from the ECS unit tests, is a test method that creates a new City instance and sets and tests its name field. It concludes by checking that the instance's title is the same as the value held by the name field:

public void testCity() {
	View city = getClassView("Cities").newInstance();
	city.testField("Name", "Boston");
	city.assertTitleEquals(city.getFieldTitle("Name"));
}

This second example tests the initial state of a booking object. It expects to have two read only fields, a specific status value, and four associations that do not yet refer to anything. Because of this state it also specifies that the Confirm option is to be disabled:

public void testBooking() {
	View booking = getClassView("Bookings").newInstance();
	booking.assertFieldReadOnly("Reference");
	booking.assertFieldReadOnly("Status");
	
	booking.assertFieldContains("Status", "New Booking");
	
	booking.assertCantRightClick("Confirm");
	
	booking.assertFieldContains("Customer", (View)null);
	booking.assertFieldContains("City", (View)null);
	booking.assertFieldContains("Pick Up", (View)null);
	booking.assertFieldContains("Drop Off", (View)null);
}

As in the two examples above, most tests will need to access the class objects before any useful testing can be done. The org.nakedobjects.testing.ApplicationTestCase class provides a method to get hold of the class view for a particular class:

  • public ClassView getClassView(String name) retrieves a class view using the class name as it is known to the user (e.g. "Credit Cards" for the CreditCard class).

Object views are used to simulate user actions as discussed in the previous section. Additional assert... methods are provided within these views to help check fields and titles:

  • public void assertTitleEquals(String message, String expectedTitle) compares the title of the view, which is the text provided by the view's object's title method, with the expected title. It throws an junit.framework.AssertionFailedError, which includes the supplied message, if the resultant strings are different.
  • public void assertTitleEquals(String expectedTitle) is the same as the previous method, but without the failure message.
  • public void assertFieldContains(String message, String fieldName, String expectedValue) checks the named field to confirm that it contains the expected value. If the field's value is different then an AssertionFailedError is thrown, and includes the supplied message.
  • public void assertFieldContains(String fieldName, String expectedValue) is the same as the previous method, but without the failure message.
  • public void assertFieldReadOnly(String fieldName) checks the named field to confirm that it is not editable. If the field is editable then an AssertionFailedError is thrown.
  • public void assertFieldContains(String message, String fieldName, View expected) checks the named field to confirm that it contains the same object as the expected view. If the value of expected is null then the field is also expected to contain null.
  • public void assertFieldContains(String fieldName, View expected) is the same as the previous method, but without the failure message.
  • public void assertCantRightClick(String message, String option) checks that the named option cannot be selected. If the option does not exist or it is enabled an AssertionFailedError is thrown, and includes the supplied message.
  • public void assertCantRightClick(String option) is the same as the previous method, but without the failure message.
  • public void assertCantDrop(String message, DragView dropObject) checks that the specified object (contained by the view) cannot be dropped onto the current view. If the drop object can be dropped on this view, an AssertionFailedError is thrown, including the supplied message.
  • public void assertCantDrop(DragView dropObject) is the same as the previous method, but without the failure message.

In addition to these explicit assertions there are three methods that test a field by assigning a value or an object to it and then, using the above assert methods, confirm that the information was stored properly. As for the previous methods, if the field does not exist then an exception will be thrown:

  • public void testField(String fieldName, String value) tests the named attribute field by attempting to set it using the value specified in value. Once set, the value held by the object is accessed and compared to the same value.
  • public void testField(String fieldName, String value, String expected) tests the named value field by attempting to set it using the value specified in value. Once set, the value held by the object is accessed and compared to the value in expected. This can be used to compensate for value objects that manipulate the set value before storing it. For example, the date object allows you specify a number of days to add to the date. So if the original date was '5-Mar-01', then after setting with it with the value '+14' the date would be '19-Mar-01'.
  • public void testField(String fieldName, View setObject) tests the named association field by attempting to set it using the object contained in the specified view and then comparing the reference held by the field to the original reference.