License     Codehaus     OpenEJB     OpenJMS     OpenORB     Tyrex     

Main
  Home
  About
  Features
  Download
  Dependencies
  Maven 2 support
  Maven 2 archetypes
  DTD & Schemas
  News Archive
  RSS news feed

Documentation
  Reference guide
  Publications
  JavaDoc
  Project Wiki
  Recent changes

Development/Support
  Mailing Lists
  SVN/JIRA
  Contributing
  Support
  Continuous builds
  Prof. services

Related projects
  Spring ORM support
  Spring XML factories
  WS frameworks

Tools
  Schema generator

More
  The Examples
  3rd Party Tools
  JDO Tests
  XML Tests
  Configuration
 
 

About
  License
  User stories
  Contributors
  Marketplace
  Status, Todo
  Changelog
  Library
  Contact
  Project Name

  



The Castor Testing Framework: Test Suite Execution and Test Creation

Documentation Author(s):
Arnaud Blandin
Sebastien Gignoux
Edward Kuns

This document describes the Castor Testing Framework, how to execute it, what test suites exist, and how, when, and where to add a test.


Abstract
Introduction
Overview of the CTF
    Creating a JUnit test case
    Repository architecture
    CTF Test Patterns
        CTF Test Types
        Schema Test Patterns
        Marshaling Test Patterns
        Only Source Generation Test Patterns
        Source Generation Test Patterns
    Life Cycle of a CTF Test
Building the CTF
Running the CTF
    Command Line options
The Test Description: TestDescriptor.xml
    Header
    The Test (Following the Header)
        SchemaTest
        MarshallingTest
        OnlySourceGenerationTest
        SourceGeneratorTest
    UnitTestCase
    Listener
    Configuration
    Call-Method
Implementing CastorTestable
    dumpFields
    randomizeFields
    Sample Java Class for a Root_Object
Implementing ObjectModelBuilder
    buildInstance
    Sample Java Class for an Object Builder
Reporting a bug in Castor
Full Sample of a Source Generation Test
    TestDescriptor.xml
    The gold file
    PrimitivesBuilder.java
    Launching the Test
        Launching the Test from a JAR
        Launching the Test from a directory tree
Full Sample of a Marshaling Framework Test
Checklist for creating a CTF test
Status of the CTF
XML Schema for TestDescriptor.xsl
References


Abstract

Test Automation is often seen as very useful but tedious task. However the limited number of test templates for Castor makes it easy to implement. The aim of this document is to describe the Castor Testing Framework by giving an overview of its functionalities and by providing detailed example test cases.

Introduction

One of the main processes in the life cycle of software is the 'validation and verification' process. It is a central process that checks that the requisite functions exist and that there are no faults. It is also known as the unpopular 'testing' process. The reliability and integrity of a software project are based on tests. Being 'open-source' does not mean that one can avoiding writing tests.

However, software testing in general consumes 30 to 70 percent of software development resources, does not find all the faults, and can be just as much work as writing the original code itself. Moreover when involved in an open-source project which includes several developers and contributors, a developer needs to write tests that can be understood by the other developers without requring a great investment of time. Ideally, these tests will highlight and test a specific feature, so if they fail the current developers can quickly understand what is broken, where the problem was introduced, and how to fix it.

One solution is to choose to automated tests: as described in Seven Steps to Automation Steps by Bret Pettichord, there are several reasons to choose to automate tests:

-Allow testing to happen more frequently,
-Improve test coverage,
-Ensure consistency, and
-Improve the reliability of testing,

For all of these reasons, we have chosen to give to Castor an automated Testing Framework called the "Castor Testing Framework" (and referered to as the CTF). This framework is built with JUnit and will help Castor developers. It also helps users in several ways by:

-Improving Castor reliability,
-Easing the monitoring of bugs, as writing bug reports will be straightforward,
-Building an archive of fixed bugs,
-Easing the creation of a test.

Overview of the CTF

In this section you will be given a quick overview of the CTF: What is the main idea behind it? Where are the tests located? What test suites exist? What are the test patterns? How do you run the tests?

Note: currently the CTF is written to test only Castor XML. A future version could test more or all of Castor functionality.

Creating a JUnit test case

Built on top of JUnit, the CTF simply creates test cases to be run under the JUnit Framework. The main idea is to provide to the CTF the minimal information needed to build test cases (such as XML Schemas, Castor mapping files, XML documents or some initialization codes for the java object model used). With this information, the CTF can then build the tests as much as possible. This means that the developer does not need to know anything about JUnit to develop a JUnit test for the CTF.

The information necessary for a test case can be located in a JAR file or in a directory structure. A directory tree will contain all the directories and jars, and the CTF will create a global test case with these individual test cases. The CTF will dynamically build the test cases located in the different jar files and pass them to JUnit.

Repository architecture

The code of Castor Testing Framework is located in the following Java packages:

          org.exolab.castor.tests.framework
          org.exolab.castor.tests.framework.testDescriptor
          org.exolab.castor.tests.framework.testDescriptor.types
        

which can be found under xmlctf/src/main/java.

The tests for testing the behavior of Castor and its main features are located in the directory tree starting at xmlctf/tests/MasterTestSuite. The tests needed to keep tracks of current reported, unfixed bugs are located in the directory tree starting at xmlctf/tests/RegressionTestSuite. The hierarchy of these test suites follows the main modules of Castor:

          MasterTestSuite     / xml / introspection
                                    / mapping
                                    / marshalling
                                    / schema
                                    / sourcegenerator
          RegressionTestSuite / xml / introspection
                                    / mapping
                                    / marshalling
                                    / schema
                                    / sourcegenerator
        

CTF Test Patterns

"Testing Castor XML" means not only testing the Marshalling Framework but also the mapping framework and the Source Generator. Thus tests fall into one of these three categories and follow several patterns defined in this section. From now on, we will use the term "gold file" to designate a file that represents an expected result. For most tests, a gold file will be an XML file.

CTF Test Types

There are four kinds of tests available for use in the CTF:

-Schema: Test schema parsing and I/O.
- Marshaling: Test XML document marshaling and unmarshaling to and from Java classes that you provide for the object model.
-Only Source Generation: Test source generation (only).
- Source Generation: Test XML document marshaling and unmarshaling to and from Java classes that are created by the Castor source generator.

Schema Test Patterns

There is only one test pattern for a Schema test. For each schema provided:

-The schema is read from disk and parsed.
-The parsed schema is optionally written to disk.
-The parsed schema is written to a new schema object in memory.
-The new schema object is compared to the original schema object read from disk.

Marshaling Test Patterns

There are three patterns used for a Marshaling test. All patterns marshal and unmarshal XML using Java classes that you provide for the object model. A Marshaling test does not use the Source Generator. A given marshaling test may use any pattern in isolation or all three patterns.

The pattern "Marshal/Unmarshal with randomized reference object" is used in isolation and is enabled/disabled separately from the other marshaling test patterns. If both other patterns ("Marshal/Unmarshal with custom instantiated reference object" and "Unmarshal/Marshal with reference XML document") are used in the same test, then the object generated by the custom class must be the same as that provided by the input XML document.

How you choose which combination of test patterns will be used is described below. When testing marshaling, you can optionally also test mapping. Thus, mapping is tested using a Marshaling test.

  1. Marshal/Unmarshal with custom instantiated reference object

    - Instantiate an object model. You provide a Java class that will instantiate and initialize an object of the correct type for the test.
    -Marshal this object to disk.
    -Compared the marshaled object to a gold file.
    -Unmarshal the document from disk.
    -Compare the unmarshaled object to the original reference object.
  2. Marshal/Unmarshal with randomized reference object

    - Instantiate an object model. The CTF will instantiate an object that is populated with random data.
    -Marshal this object to disk.
    -Compared the marshaled object to a gold file.
    -Unmarshal the document from disk.
    -Compare the unmarshaled object to the original random object.
  3. Unmarshal/Marshal with reference XML document

    -Unmarshal an XML document from disk, from an input document.
    - Optionally compare this object to one that is instantiated and initialized by a custom class that you write.
    -Marshal this object to disk.
    -Compare the newly-marshaled disk file to the input document on disk.

Only Source Generation Test Patterns

There is only one test pattern for a test of only the source generation framework. For source generation, you can optionally provide a binding file, but one is not required unless your test requires binding.

For each schema provided:

-The source generator is configured and executed against the schema.
-The generated source is compiled.
-A class loader is used to load the generated code.

Source Generation Test Patterns

There is only one test pattern for a Source Generation test. For source generation, you can optionally provide a binding file, but one is not required unless your test requires binding.

For each schema provided:

-The source generator is configured and executed against the schema.
-The generated source is compiled.
-A class loader is used to load the generated code.
- Use the generated code to execute a marshaling test. The marshaling test may use any combination of the following marshaling test patterns as described in the section "Marshaling Test Patterns":
-Marshal/Unmarshal with custom instantiated reference object
-Marshal/Unmarshal with randomized reference object
-Unmarshal/Marshal with reference XML document

Life Cycle of a CTF Test

The most basic test available in the CTF is the Schema Test. This is just the first step in the life cycle of a CTF test! Depending on whether the source generator is to be used or not, the final step is either the Marshaling test or the Source Generation test, both of which test marshaling and unmarshaling. Source generation can be also tested without marshaling -- as an intermediate step; ideally a source-generation-only test case will later become a full-fledged Castor test case by having a reference document provided so marshaling and unmarshaling can be tested.

Building the CTF

Before trying to launch the test cases, first make sure that the CTF is compiled. You can either use Subversion to check out the current trunk or you can use a source distribution from a release. Castor (and the CTF) is known to build and run under Windows and under Linux -- and Castor developers regularly test using Java JDK's between 1.3 and 5, inclusive.

Generally speaking, you build and run the CTF from within the "bin" directory of Castor's source tree. Relative to the top of the Castor source, this is the directory bin. (Pretty simple!) Just cd to that directory and you're ready to go.

Under Windows, you can use a CMD.EXE "shell" window or you can use CygWin. Which shell you use is your preference. Under UNIX, any shell will do. Change directory so the current directory is the Castor bin directory, as described above. Finally, to build the CTF, just run build.bat tests or ./build.sh tests, depending on your operating system. To be thorough, you can run build.bat clean tests or ./build.sh clean tests, which will remove previous build results and start fresh.

Note: While you can build the CTF jar -- build.bat CTFjar or ./build.sh CTFjar -- this JAR by default contains only the test framework code and no tests. The JAR is a convenient way of distributing the CTF so that someone can run it without needing access to the full Castor source. However, this document is oriented toward developers who have access to the Castor source tree. Instructions in this document don't refer to and don't use this JAR file.

Running the CTF

You can run the tests by using the script CTFRun.bat under Windows or ./CTFRun.sh under Linux/UNIX. If you want to run a specific test or small subset of tests, then you need to provide the path to that Castor Testing Framework test or test tree -- either the full path to a JAR file or a path to the root directory of a tree of tests. If you want to run the Master Test Suite, you can run the tests without providing any arguments.

The CTF currently requires the Sun JDK (or SDK) to execute, although it may be possible to execute fine with GNU gcj or with JRockit. The CTF will not work if you are using only a JRE. This is because the CTF uses the Sun Java compiler API to compile code as needed for Source Generator and Marshaling Framework tests. The CTF code is written to allow easy extension for additional compiler frameworks, so if you use a compiler or runtime that is not supported, you should be able to easily add support for a new framework. If you want to do this, contact Castor committors for assistance and direction and they'll set you on the right course.

Command Line options

Option Args Description Optional?
-verbose   Flag: Give detailed information on the progress of and execution of each test. Optional
-text   Flag: Run the tests without using the JUnit GUI. Optional
-printStack   Flag: If any Exception occurs, dumps its stack. Optional
-seed int Specifies the use of a specific seed for the pseudo-random generator. Optional

You can get information about additional command-line options provided by the shell script or batch script by executing (depending on your operating system):

CTFRun.bat help
./CTFRun.sh help

Note: The CTF scripts are current written expecting to be executed from the bin directory of Castor's source tree. The CTF may not function properly if you run these scripts from another directory.

For instance, to run all the tests from the MasterTestSuite:

CTFRun.bat -verbose ../xmlctf/tests/MasterTestSuite/sourcegenerator

This command will execute in GUI mode (the default mode) all the test cases written in the master test suite for the source generator, and will print detailed messages about the execution of the tests.

The Test Description: TestDescriptor.xml

Each CTF test case can be stored in a directory or in a jar and must contain a single TestDescriptor.xml file. This file is located under the META-INF directory when using a jar file or directly in the directory that contains the test case files when running the CTF from a directory tree. This file is a summary of the test cases contained in the directory or in the jar file.

Note: the whole XML Schema used to write TestDescriptor.xml is provided in the appendix.

The contents of the Test Descriptor are described and defined below.

Header

Every test descriptor file begins with a common header.

Tag Description Optional?
Name The name of the test Required
Author The author of the test Required
Comment Some comment on the test. This element may occur more than once. Required
Category The category in which this test falls:
-basic capability
-special case
Required
BugFix Used to report a bug and keep track of it. It is defined as follows:
-Name of the reporter
-Date of the report
- Date of the fix (if known) or of the creation of the testcase (otherwise)
-Comment on the fix (may occur more than once)
Optional

For instance, this example test descriptor header

<?xml version='1.0'?>
<TestDescriptor>
    <Name>Bug in the support of foo</Name>
    <Author>Comprehensive Contributor</Author>
    <Comment>
        This test case illustrates the bad handling of the foo element in the
        Marshaling Framework
    </Comment>
    <Comment>Adding this test will prevent further regression in this area.</Comment>
    <Category>basic capability</Category>

    <BugFix>
        <Reporter>Desperate User</Reporter>
        <Date_Report>2001-03-11T12:00:00</Date_Report>
        <Fixer>Comprehensive Contributor</Fixer>
        <Date_Fix>2053-12-12T15:03:00</Date_Fix>
    </BugFix>

     ...

</TestDescriptor>
        

is a valid header for a TestDescriptor file. You may wonder why CTF needs so much information. Actually, this information can be used to generate acceptance documents and is also used to archive and track different resolved bugs. The comment fields especially are present for developers and interested users and are not directly used during the testing process.

The Test (Following the Header)

The content of TestDescriptor.xml following the header differs depending on the test type:

Tag Description Optional?
Name The name of the test Required
Author The author of the test Required
Comment Some comment on the test. This element may occur more than once. Required
The test itself Exactly one of a SchemaTest, MarshallingTest, OnlySourceGenerationTest, or SourceGeneratorTest. Required

SchemaTest

A SchemaTest tests only that the provided schema(s) can be successfully read and parsed, and then written to disk. No marshaling or unmarshaling or source generation is performed.

Tag Attributes Description Optional?
UnitTestCase   One or more unit test cases (see below) Required

MarshallingTest

A MarshallingTest will unmarshal the source document, then marshal it to a new file, then unmarshal the new document and compare to the original. No source generation is performed. The Castor marshaling framework is used.

If the root object has the attribute random, then additionally a randomized object will be created, marshaled, then unmarshaled, and the unmarshaled object will be compared to the original random object.

Tag Attributes Description Optional?
Root_Object
- dump: a boolean indicating that dumpFields() method has been implemented in Root_Object and that the unmarshaled objects should be dumped.
- random: a boolean indicating that randomizeFields() method has been implemented in Root_Object and that a randomized object should be created, marshaled, and unmarshaled for comparison.
The qualified name of the Root object in the generated object model Required
Configuration   Marshal/Unmarshal configuration (see below) Optional
UnitTestCase   One or more unit test cases (see below) Required

OnlySourceGenerationTest

An OnlySourceGenerationTest will run the Castor source generator on the schema(s) provided, will compile the generated source, and will load (via a class loader) the compiled source. No marshaling or unmarshaling will be done.

Tag Attributes Description Optional?
Schema None The name of the schema from which we generate sources, may occur more than once Required
Property_File None The name of the Source Generator property file (often named castorbuilder.properties) to use Optional
Collection None The collection type to use (usually 'vector' or 'arraylist' or 'odmg'); if absent, defaults to 'vector' Optional
Binding_File None The name of the binding file (if any) Optional
UnitTestCase   One or more unit test cases (see below) Required

SourceGeneratorTest

A SourceGeneratorTest will run the Castor source generator on the schema(s) provided, will compile the generated source, and will load (via a class loader) the compiled source. Once this has been done successfully, the generated source will be used to unmarshal an XML document. The document will then be marshaled to a new file, and then unmarshaled from that file. The newly unmarshaled document will be compared to the original.

If the root object has the attribute random, then additionally a randomized object will be created, marshaled, then unmarshaled, and the unmarshaled object will be compared to the original random object.

Tag Attributes Description Optional?
Schema None The name of the schema from which we generate sources, may occur more than once Required
Property_File None The name of the Source Generator property file (often named castorbuilder.properties) to use Optional
Collection None The collection type to use (usually 'vector' or 'arraylist' or 'odmg'). if absent, defaults to 'vector' Optional
Binding_File None The name of the binding file (if any) Optional
Root_Object
- dump: a boolean indicating that dumpFields() method has been implemented in Root_Object and that the unmarshaled objects should be dumped.
- random: a boolean indicating that randomizeFields() method has been implemented in Root_Object and that a randomized object should be created, marshaled, and unmarshaled for comparison.
The qualified name of the Root object in the generated object model Required
UnitTestCase   One or more unit test cases (see below) Required

UnitTestCase

This is the core of the test, this element provides the input file and output file used for a specific test and the name of the class used to instantiate the Object Model. Once again remember that a TestDescriptor.xml describes a test for a general behavior of Castor which may imply several test cases.

Tag Attributes Description Optional?
Name None The name of this test. Required
Mapping_File None The mapping file for this test, if any. This element is used only for a MarshallingTest, and should be absent for other test types. Optional
Schema None The schema to be used for this test. This element is used only for a SchemaTest, and should be absent for other test types. You can specify only one schema. Alternately, if the value of this element is "*" then all schemas (identified by the extension .xsd) in the directory or JAR containing the TestDescriptor.xml will be included. Optional
Configuration   Configuration for Marshaling or Unmarshaling (see below) Optional
Input None The name of the input file used to create a specific Object Model by unmarshaling this file, used in the "test with reference document" test. You need to provide this element for the MarshallingTest and the SourceGeneratorTest. It is not used for the other test types. Optional, depending on test type
GoldFile None The name of the file which can be seen as a "gold file." This element is used only in a MarshallingTest in the "test with reference document" test and is ignored for other test types. This element is optional for a MarshallingTest. If it is present, then the marshaled reference document is compared to the gold file. Optional
ObjectBuilder None The fully-qualified class name of the class used to instantiate the Object Model used. This can be used in addition to an input document, as a way of generating an additional document to compare against. This element is optional for the MarshallingTest or SourceGeneratorTest (if present, used for the "test with reference document" test) and is not used for other test types. If it is present, then the named class is instantiated. Once instantiated, the method buildInstance() is invoked. The object returned is compared against the unmarshaled input file. That is, the ObjectBuilder is used to create a reference document. Optional
Failure
- exception: The class name of an exception. If Failure is false, this attribute is ignored. If Failure is true and this optional attribute is present, then the test will succeed only if the named Exception is thrown and the test will fail otherwise. If Failure is true and this attribute is absent, then the test will succeed if any Exception is thrown.
A boolean. If true, the test will pass if an exception is thrown. Otherwise, the test will fail if an exception is thrown. Optional
Skip None A boolean. If true, this test will be skipped. Optional
Listener   A listener for this test (see below). A Listener is used only for a MarshallingTest (it might also work for a SourceGeneratorTest but it has not been tested). A Listener should be absent for other test types. Optional

Listener

Tag Description Optional?
ClassName The name of the class to use for MarshalListener and/or UnmarshalListener Required
Type Marshal, Unmarshal or Both. Indicate how to use the provided ClassName. Optional, defaults to "Both".
GoldFile The name of the file which can be seen as a 'gold file' Optional

Configuration

Tag Description Optional?
Marshal If present, the Marshaler will be configured Optional
Unmarshal If present, the Unmarshaler will be configured Optional

Call-Method

Tag Attributes Description Optional?
Call-Method
- name: the name of the method to call on the Marshaler or Unmarshaler.
Root tag for defining a method call Required
Value
- type: the fully qualified name of the java type representing an argument of the method. For a primitive type, use the name of the primitive type.
The value to be passed in to the method called (this element can occur more than once). Optional

The following code excerpt illustrates how to configure the Marshaler by suppressing all the XSITypes.

<Configuration>
    <Marshal>
        <Call-method name="setSuppressXSIType">
            <Value type="boolean">true</Value>
         </Call-method>
    </Marshal>
</Configuration>
      

Please note that the Configuration element can be present at the MarshallingTestCase level and at the UnitTestCase level. If it is found in both places, the only the UnitTestCase configuration is used.

Implementing CastorTestable

As you may have noticed, while testing the SourceGenerator or the Marshaling Framework you have to provide the name of the 'Root Object' of your Object Model. The Root Object represents the mapping of the root element of the XML document.

For instance, given the following XML document:

<?xml version='1.0'?>
<Invoice>
    <Customer>
        ...
    </Customer>
    <Items>
        ...
    </Items>
      ...
</Invoice>
      

the class that represents the Root Object is Invoice.

You provide your own implementation of a Root Object only for a test of the Marshaling framework. For a Source Generation framework test, the appropriate interface is automatically implemented in the generated source. Thus, the discussion below really only applies to a MarshallingTest type of CTF test.

The CTF needs your Root Object to override the equals() method of the java.lang.Object class. This is required, not optional, and is used when comparing object models.

While not strictly required, it is highly recommended that the Root Object implement the interface org.exolab.castor.tests.framework.CastorTestable. Implementing this interface is simple: implement two methods: dumpFields() and randomizeFields(). These methods are described below.

dumpFields

Here is the JavaDoc of the method as defined in the interface:

    /**
     * Return a recursive dump of the content of the
     * object fields in a user readable format.
     * This is used to retrieve the state of the object if
     * castor fail to marshal the object for any reason.
     *
     * We don't rely on the toString() function as it could have
     * been already implemented with another semantic.
     */
        

randomizeFields

Here is the JavaDoc of the method as defined in the interface:

    /**
     * The instance of the object will randomize the content
     * of its field. This is used to create an instance
     * of the object model without having to
     * unmarshal anything.
     */
        

In order to tell the CTF that one (or both) of these methods is implemented you have to set the attributes "dump" and "random" to true in the Root_Object element of the test descriptor:

<Root_Object dump='true' random='true'>Root</Root_Object>

Note: When using the Source Generator outside the CTF, you can automatically generate classes that implements CastorTestable by using the command line option "-testable". Within the CTF and the source generator-based tests, this option is automatically provided to the source generation framework.

Sample Java Class for a Root_Object

The following is an example of a Root Object suitable for use in a MarshallingTest Marshaling framework test.

import java.util.Vector;
import java.util.Enumeration;

// CTF specific
import org.exolab.castor.tests.framework.CastorTestable;

// Provide the necessary methods to randomly create object fields
import org.exolab.castor.tests.framework.RandomHelper;

public class Root implements CastorTestable {
    private String _name;
    private Vector _data;
    public void setName(String name) {
        _name = name;
    }
    public String getName() {
        return _name;
    }
    public void setData(Vector data) {
        _data = data;
    }
    public Vector getData() {
        return _data;
    }

    // --- CastorTestable ------------------------
    public String dumpFields() {
        StringBuffer fields = new StringBuffer();
        fields.append("name=" + _name + "; data=\n");
        for (Enumeration e = _data.elements(); e.hasMoreElements(); ) {
            CastorTestable element = (CastorTestable)e.nextElement()
            fields.append("[" + element.dumpFields() + "]\n");
        }
        return fields.toString();
    }

    public void randomizeFields() throws InstantiationException,
                                         IllegalAccessException {
        _name = RandomHelper.rndString();
        _data = RandomHelper.rndVector(_data, Data.class);
    }

    /**
     * Note: We should override hashCode() but have not.
     * @param obj
     */
    public boolean equals(java.lang.Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof Root) {
            Root temp = (Root)obj;
            if (!(this._name.equals(temp._name))) {
                return false;
            }
            if (!(this._data.equals(temp._data))) {
                return false;
            }
            return true;
        }
        return false;
    } //-- boolean equals(java.lang.Object)

} //Root
        

Implementing ObjectModelBuilder

For a MarshallingTest or a SourceGeneratorTest, in addition to an input document (for unmarshaling), you can also provide an object that will directly and programmatically (not from a file) construct your desired test document. This is a class that will instantiate and correctly populate your test object. This class must implement equals()! It will be compared against your unmarshaled input document.

It's recommended that your Object Model Builder also implement the interface CastorTestable, but this is not required.

buildInstance

Here is the JavaDoc of the method declaration in the interface:

    /**
     * Generates and returns a new instance from the hard-coded data.
     *
     * @return a new instance from the hard-coded data
     * @throws Exception if anything goes wrong creating the instance
     */
        

Sample Java Class for an Object Builder

The following is an example of an Object Builder suitable for use in a MarshallingTest or SourceGeneratorTest. The class Root used here would be generated for you if you are creating a SourceGeneratorTest, but would be provided by you for a MarshallingTest. This is the Root Object of the test.

import java.util.Vector;

// CTF specific
import org.exolab.castor.tests.framework.ObjectBuilder;

public class Builder implements ObjectBuilder {
    /**
     * Build the expected object model.
     */
    public Object buildInstance() {
        Root r = new Root();
        r.setName("object name");
        Vector v = new Vector(3);
        v.add(new Data("CASTOR-XML", "good"));
        v.add(new Data("CASTOR-JDO", "good"));
        v.add(new Data("CASTOR-DAX", "to be improved"));
        r.setData(v);
        return r;
    }
} //Builder
        

Reporting a bug in Castor

With the CTF, reporting a bug should be easier. You should no longer need to find yourself in endless discussion in describing the bug you encounter. All you have to do is:

-Write a simple test case as described previously.
-Create a jar or a directory tree (which you can ZIP up).
- Send it to the Exolab JIRA or to a contributor:
Exolab JIRA: http://jira.codehaus.org/browse/CASTOR
Committer list: http://castor.codehaus.org/contributors.html

Full Sample of a Source Generation Test

In this section, we demonstrate a complete test case for the Source Generator. The sample test tests the handling of primitives W3C XML Schema type in the Source Generator using the default properties of the Source Generator. This test just illustrates that the Source Generator supports primitives types.

First we have to create the TestDescriptor xml file:

TestDescriptor.xml

The test descriptor just describes the test case:

<?xml version='1.0'?>
<TestDescriptor>
    <Name>Test primitive types with default properties</Name>
    <Comment>
        Test W3C XML Schema primitives type handling in the Source Generator
    </Comment>
    <Comment>The supported types are:
                            -string
                            -boolean
                            -decimal
                            -float
                            -double
                            -duration
                            -dateTime
                            -time
                            -gYearMonth
                            -gYear
                            -gMonthDay
                            -gDay
                            -gMonth
                            -hexBinary
                            -base64Binary
                            -anyURI
                            -QName
    </Comment>
    <Comment>
        The facets are not tested in this case and Java primitives are used.
    </Comment>
    <Comment>hexBinary and base64Binary are not tested.</Comment>

    <Category>basic capability</Category>

    <SourceGeneratorTest>
        <Schema>primitives.xsd</Schema>
        <Root_Object random="true" dump="true">TestPrimitives</Root_Object>
        <UnitTestCase>
            <Name>Test Generation</Name>
            <Input>input1.xml</Input>
        </UnitTestCase>
        <UnitTestCase>
            <Name>Test Marshalling with the generated Descriptors</Name>
            <Input>input1.xml</Input>
            <ObjectBuilder>PrimitivesBuilder</ObjectBuilder>
        </UnitTestCase>
        <UnitTestCase>
            <Name>Test the validation</Name>
            <Input>badinput.xml</Input>
            <Failure>true</Failure>
        </UnitTestCase>
    </SourceGeneratorTest>
</TestDescriptor>
        

Once we have the Test Descriptor, we have to provide the primitives.xsd and input1.xml and badinput.xml files as referenced in the Test Descriptor. We don't need to worry about implementing CastorTestable since the SourceGenerator will do so for us: it automatically generates the dumpFields() and randomizeFields() methods.

Because we want to provide a thorough example, we also want to provide an instance builder, i.e., implementing the ObjectBuilder interface, as referenced in the Test Descriptor.

The gold file

<?xml version="1.0"?>
<TestPrimitives StringTestAtt="StringAttribute" booleanTestAtt="false"
                floatTestAtt="3.141526" doubleTestAtt="1.171077"
                decimalTestAtt="123456789.987654321"
                uriReferenceTestAtt="http://www.castor.org"
                IDTestAtt="Castor0.91" QNameTestAtt="xsd:type">
    <StringTestEle>StringElement</StringTestEle>
    <booleanTestEle>true</booleanTestEle>
    <floatTestEle>1234567899876543210</floatTestEle>
    <doubleTestEle>0.6385682166079459</doubleTestEle>
    <decimalTestEle>0.2693678757526658529286578414030373096466064453125</decimalTestEle>
    <timeDurationTestEle>P1Y2M3DT4H5M6S</timeDurationTestEle>
    <uriReferenceTestEle>http://castor.exolab.org</uriReferenceTestEle>
    <IDTestEle>ID9</IDTestEle>
    <QNameTestEle>Test:test</QNameTestEle>
</TestPrimitives>
        

PrimitivesBuilder.java

PrimitivesBuilder.java is a simple implementation of ObjectBuilder. It contains the hard-coded values of the input xml file, it is used to create a "gold" Object Model we can use to compare the Object Model created from the unmarshalling of "input1.xml."

import java.util.Vector;

//the interface we implement
import org.exolab.castor.tests.framework.ObjectBuilder;

public class PrimitivesBuilder implements ObjectBuilder {
    /**
     * Build the object expected when unmarshalling 'input1.xml'.
     */
    public Object buildInstance() {
        TestPrimitives test = new TestPrimitives();
        test.setStringTestAtt("StringAttribute");
        test.setBooleanTestAtt(false);
        test.setFloatTestAtt(3.141526f);
        test.setDoubleTestAtt(1.171077);
        ...
        return test;
    }
}
        

Launching the Test

The last step consists of packaging up the collection of files that make up the test case. You have two choices. You can either create a JAR file containing the test, or you can create a directory structure containing the test. You can use whichever option is easier.

Launching the Test from a JAR

Create a JAR from your test's source files:

   jar cvf ../PrimitivesWithoutFacets.jar *.*
          

You can now execute this test by running the CTF with the path to this JAR file:

   CTFRun -verbose PrimitivesWithoutFacets.jar
          

Launching the Test from a directory tree

Create a new directory under the appropriate test suite directory tree. For this test, an appropriate directory would be: xmlctf/tests/MasterTestSuite/sourcegenerator/PrimitivesWithoutFacets. Copy all of the files that comprise your test into that directory.

You can now execute this test by running the CTF with the path to this directory:

CTFRun -verbose ../xmlctf/tests/MasterTestSuite/sourcegenerator/PrimitivesWithoutFacets
          

Full Sample of a Marshaling Framework Test

To be written....

Checklist for creating a CTF test

-Create a directory (the test directory) to put the files needed for the test case.
-Create the META-INF directory in this directory.
-Create your TestDescriptor.xml.
-Write the XML schema, mapping file or XML documents needed and put them under your test directory.
-If you provide an Object Model don't forget to override the equals() method
-If necessary, implement the dumpFields() and randomizeFields() methods.
-Compile the provided object model
-Create a jar representing the test directory
-Run the test

Status of the CTF

The current version of the CTF is not perfect and could use some improvements. However, it provides a solid base upon which to test the behavior of Castor. And its presence will help developers to avoid regression while fixing bugs and adding new features.

Future versions of the CTF may include:

-A tool to generate test acceptance documents,
-An updated architecture for RandomHelper,
-A way to launch the test from the web site, and
-Better exception handling and failure tests.

XML Schema for TestDescriptor.xsl

The full source of the W3C XML schema for the TestDescriptor object is included below. It is found in the source file TestDescriptor.xml. Note that this schema is a work in progress and is subject to change.

      
      
<?xml version='1.0' encoding="UTF-8"?>
<!--
    Castor Testing Framework Test Descriptor XML Schema
    Namespace: http://castor.exolab.org/Test

    This schema is used to generate the
    org.exolab.castor.tests.framework.testdescriptor package
    *Note*: This schema is under evolution and subject to change.
     This schema is under the Exolab license
 -->
<!-- $Id: ctf.xml 9173 2013-02-25 10:04:44Z wguttmn $ -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://castor.exolab.org/Test"
            xmlns:test="http://castor.exolab.org/Test"
            elementFormDefault="qualified">

    <!-- The root element which contains an header and a test element-->
    <xsd:element name="TestDescriptor">
        <xsd:annotation>
            <xsd:documentation>
                Castor Testing Framework Test Descriptor XML Schema
                &lt;p>
                Namespace: http://castor.exolab.org/Test
                &lt;p>
                This schema is used to generate the
                org.exolab.castor.tests.framework.testdescriptor package
                *Note*: This schema is under evolution and subject to change.
                 This schema is under the Exolab license.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:sequence>
                <!-- The name of the test -->
                <xsd:element name="Name" type="xsd:string" minOccurs="1" maxOccurs="1"/>
                <!-- The author of the tests -->
                <xsd:element name="Author" type="xsd:string" minOccurs="1" maxOccurs="1"/>
                <!-- Some comments for describing the test -->
                <xsd:element name="Comment" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
                <!-- Define the category of the test -->
                <xsd:element name="Category" type="test:CategoryType" minOccurs="1" maxOccurs="1"/>
                <!-- Is it a bug fix?-->
                <xsd:element ref="test:BugFix" minOccurs="0" maxOccurs="1"/>
                <!-- Test for the SourceGenerator OR the Marshaling Framework-->
                <xsd:choice>
                    <!-- Test case for the SourceGenerator -->
                    <xsd:element ref="test:SourceGeneratorTest" minOccurs="0" maxOccurs="1"/>
                    <!-- Test case for the Marshaling Framework -->
                    <xsd:element ref="test:MarshallingTest" minOccurs="0" maxOccurs="1"/>
                    <!-- Test case for the Schema Object Model -->
                    <xsd:element ref="test:SchemaTest" minOccurs="0" maxOccurs="1"/>
                    <!-- Test case for Source Generation ONLY (no marshaling or unmarshaling) -->
                    <xsd:element ref="test:OnlySourceGenerationTest" minOccurs="0" maxOccurs="1"/>
                </xsd:choice>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="BugFix">
        <xsd:annotation>
            <xsd:documentation>
                Encapsulates information about a bug fix, including the reporter's
                name (or Email address), the date of the report and of the fix,
                and one or more comments about the bug.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:sequence>
                <!-- the reporter name or EMail address-->
                <xsd:element name="Reporter" type="xsd:string" minOccurs="1" maxOccurs="1"/>
                <!-- date of the report-->
                <xsd:element name="Date_Report" type="xsd:date" minOccurs="1" maxOccurs="1"/>
                <!-- date of the fix-->
                <xsd:element name="Date_Fix" type="xsd:date" minOccurs="1" maxOccurs="1"/>
                <!-- Some comments on the fix or the bug -->
                <xsd:element name="Comment" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="SourceGeneratorTest">
        <xsd:annotation>
            <xsd:documentation>
                Tests source generation and then tests the generated source, testing
                both marshaling and unmarshaling.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:sequence>
                <!-- the names of the schema files to generate sources from-->
                <!-- assume that the Testing Framework will try to match the name -->
                <!-- by looking in all the JARs - directories -->
                <xsd:element name="Schema" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
                <!-- The name of the properties file used with this SourceGenerator test case-->
                <xsd:element name="Property_File" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                <!-- The name of the collection type used with this SourceGenerator test case-->
                <xsd:element ref="test:Collection" minOccurs="0" maxOccurs="1"/>
                <!-- the binding file name -->
                <xsd:element name="BindingFile" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                <!-- the qualified name of the root Object -->
                <!-- later: define a pattern to describe a Java quailified name-->
                <xsd:element ref="test:Root_Object" minOccurs="1" maxOccurs="1"/>
                <!-- individual test cases -->
                <xsd:element ref="test:UnitTestCase" minOccurs="1" maxOccurs="unbounded"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="MarshallingTest">
        <xsd:annotation>
            <xsd:documentation>
                Test marshaling.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:sequence>
                <!-- the qualified name of the root Object -->
                <!-- later: define a pattern to describe a Java quailified name-->
                <xsd:element ref="test:Root_Object" minOccurs="0" maxOccurs="1"/>
                <!-- the configuration for the marshaling framework -->
                <xsd:element ref="test:Configuration" minOccurs="0" maxOccurs="1"/>
                <!-- individual test cases -->
                <xsd:element ref="test:UnitTestCase" minOccurs="1" maxOccurs="unbounded"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="SchemaTest">
        <xsd:annotation>
            <xsd:documentation>
                Tests a schema.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:sequence>
                <!-- individual test cases -->
                <xsd:element ref="test:UnitTestCase" minOccurs="1" maxOccurs="unbounded"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="OnlySourceGenerationTest">
        <xsd:annotation>
            <xsd:documentation>
                Tests source generation only, and does not attempt to use the generated code.  While
                a <code>SourceGeneratorTest</code> is better because it is more thorough, sometimes
                the only thing that requires testing is the code generation.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:sequence>
                <!-- the names of the schema files to generate sources from-->
                <!-- assume that the Testing Framework will try to match the name -->
                <!-- by looking in all the JARs - directories -->
                <xsd:element name="Schema" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
                <!-- The name of the properties file used with this SourceGenerator test case-->
                <xsd:element name="Property_File" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                <!-- The name of the collection type used with this SourceGenerator test case-->
                <xsd:element ref="test:Collection" minOccurs="0" maxOccurs="1"/>
                <!-- the binding file name -->
                <xsd:element name="BindingFile" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                <!-- individual test cases -->
                <xsd:element ref="test:UnitTestCase" minOccurs="1" maxOccurs="unbounded"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="Root_Object" type="test:RootType">
        <xsd:annotation>
            <xsd:documentation>
                The qualified name of the root Object.
                TODO: define a pattern to describe a Java quailified name.
            </xsd:documentation>
        </xsd:annotation>
    </xsd:element>

    <xsd:element name="Collection" default="vector">
        <xsd:annotation>
            <xsd:documentation>
                The data type to use in collections.
            </xsd:documentation>
        </xsd:annotation>
           <xsd:simpleType>
            <xsd:restriction base="xsd:string">
                <xsd:enumeration value="vector"/>
                <xsd:enumeration value="arraylist"/>
                  <xsd:enumeration value="odmg"/>
            </xsd:restriction>
        </xsd:simpleType>
    </xsd:element>

    <xsd:element name="UnitTestCase">
        <xsd:annotation>
            <xsd:documentation>
                A definition of a single Unit Test testcase.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:sequence>
                <!-- The name of the test -->
                <xsd:element name="Name" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                <xsd:choice minOccurs="0">
                    <!-- the mapping file used (if any) -->
                    <xsd:element name="Mapping_File" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                    <!-- the name of the schema to read/write -->
                    <!-- a '*' will indicate that the CTF will try to read/write -->
                    <!-- all the schemas present in the directory or jar -->
                    <xsd:element name="Schema" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                </xsd:choice>
                <!-- the configuration for the marshalling framework -->
                <xsd:element ref="test:Configuration" minOccurs="0" maxOccurs="1"/>
                <!-- the input XML file for unmarshaling -->
                <xsd:element name="Input" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                <!-- the file to compared a marshaled document to -->
                <xsd:element name="GoldFile" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                <!-- the ObjectBuilder class used for this test case -->
                <xsd:element name="ObjectBuilder" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                <!-- a boolean that indicates if the test case intents to fail (Exception thrown)-->
                <xsd:element name="Failure" type="test:FailureType" minOccurs="0" maxOccurs="1"/>
                <!-- will cause the test to be ignored -->
                <xsd:element name="Skip"   type="xsd:boolean" minOccurs="0" maxOccurs="1"/>
                <!-- the listener to use for unmarshaling, marshaling or both -->
                <xsd:element name="Listener" type="test:ListenerType" minOccurs="0" maxOccurs="1"/>
                <!-- for a schema test, the number of differences expected -->
                <xsd:element name="SchemaDifferences" type="test:SchemaDifferencesType"
                             minOccurs="0" maxOccurs="2"/>
                <!-- Some comments for describing the test -->
                <xsd:element name="Comment" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="Configuration">
        <xsd:annotation>
            <xsd:documentation>
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
           <xsd:choice>
              <xsd:element name="Marshal" type="test:ConfigurationType"/>
              <xsd:element name="Unmarshal" type="test:ConfigurationType"/>
           </xsd:choice>
        </xsd:complexType>
    </xsd:element>

    <xsd:complexType name="ConfigurationType">
        <xsd:annotation>
            <xsd:documentation>
                Configuration for marshaling or unmarshaling or source generation.  Contains
                a list of methods to be called on the marshaler or unmarshaler or source
                generator with the parameters to be provided for each method.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:sequence>
           <xsd:element ref="test:Call-method" maxOccurs="unbounded"/>
        </xsd:sequence>
    </xsd:complexType>

    <xsd:element name="Call-method">
        <xsd:annotation>
            <xsd:documentation>
                A single method to call on a marshaler or unmarshaler or source generator
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element ref="test:Value" maxOccurs="unbounded"/>
            </xsd:sequence>
            <!-- the name of the method to call -->
            <xsd:attribute name="name" type="xsd:string"/>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="Value">
        <xsd:annotation>
            <xsd:documentation>
                A parameter to be provided to a method.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:simpleContent>
                <xsd:extension base="xsd:string">
                    <!-- java type -->
                    <xsd:attribute name="type" type="xsd:string" required="true"/>
                </xsd:extension>
            </xsd:simpleContent>
        </xsd:complexType>
    </xsd:element>

    <xsd:simpleType name="CategoryType">
        <xsd:annotation>
            <xsd:documentation>
                The type of test case, either basic capability or a special case.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="basic capability"/>
            <xsd:enumeration value="special case"/>
            <!-- Extensible-->
        </xsd:restriction>
    </xsd:simpleType>

    <!--A root object in an object model-->
    <xsd:complexType name="RootType">
        <xsd:annotation>
            <xsd:documentation>
                The definition of the Root Type in the object model.  Contains two
                boolean attributes:  <code>random</code> and <code>dump</code>.
                If random is set to true, a test using randomized objects will
                be executed.  If dump is set to true, the object will be dumped
                to specific files.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexContent>
            <xsd:extension base="test:StringType">
                <!--set to true to randomly generate the given Object Model-->
                <xsd:attribute name="random" type="xsd:boolean" default="false"/>
                <!--set to true to dump the given Object Model states in specific files-->
                <xsd:attribute name="dump"   type="xsd:boolean" default="false"/>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="StringType">
        <xsd:annotation>
            <xsd:documentation>
                A Java String.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:simpleContent>
            <xsd:extension base="xsd:string"/>
        </xsd:simpleContent>
    </xsd:complexType>

    <!-- The failure type -->
    <xsd:complexType name="FailureType">
        <xsd:annotation>
            <xsd:documentation>
                True if this test is expected to throw an Exception and if it would thus
                be an error if the test does not throw an Exception.  False otherwise.
                &lt;p>
                If FailureType is true, then this element optionally contains the attribute
                <code>exception</code> that contains the class of the Exception that is
                expected.  If this attribute is not provided, then the presence of any
                exception causes the test to pass.  Otherwise, the specific exception
                has to be thrown for the test to pass.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:simpleContent>
            <xsd:extension base="xsd:boolean">
                <!-- if you expect a specific exception, you can specify it here -->
                <xsd:attribute name="exception" type="xsd:string" use="optional"/>
                <!-- if you expect the failure at a specific step, specify which step -->
                <xsd:attribute name="FailureStep" type="test:FailureStepType" use="optional"/>
            </xsd:extension>
        </xsd:simpleContent>
    </xsd:complexType>

    <!-- The failure type -->
    <xsd:complexType name="SchemaDifferencesType">
        <xsd:annotation>
            <xsd:documentation>
                If you expect a non-zero number of differences when comparing schemas,
                add one of these elements and provide the FailureStep attribute
                to say which step this difference applies to.
            </xsd:documentation>
        </xsd:annotation>
        <xsd:simpleContent>
            <xsd:extension base="xsd:int">
                <xsd:attribute name="FailureStep" type="test:FailureStepType" use="required"/>
            </xsd:extension>
        </xsd:simpleContent>
    </xsd:complexType>

    <xsd:simpleType name="FailureStepType">
       <xsd:restriction base="xsd:string">
           <xsd:enumeration value="parse-schema"/>
           <xsd:enumeration value="write-schema"/>
           <xsd:enumeration value="compare-schema"/>
           <xsd:enumeration value="source-generation"/>
           <xsd:enumeration value="source-compilation"/>
           <xsd:enumeration value="load-generated-classes"/>
           <xsd:enumeration value="unmarshal-reference"/>
           <xsd:enumeration value="marshal-to-disk"/>
           <xsd:enumeration value="compare-to-reference"/>
           <xsd:enumeration value="second-compare"/>
           <xsd:enumeration value="listener-comparison"/>
           <xsd:enumeration value="second-unmarshal"/>
       </xsd:restriction>
    </xsd:simpleType>

    <!-- Marshal/Unmarshal Listener type -->
    <xsd:complexType name="ListenerType">
        <xsd:annotation>
            <xsd:documentation>
            </xsd:documentation>
        </xsd:annotation>
        <xsd:sequence>
            <xsd:element name="GoldFile" type="xsd:string" maxOccurs="1"/>
            <!-- the fully qualified name for the listener -->
            <xsd:element name="ClassName" type="xsd:string" minOccurs="1" maxOccurs="1"/>
            <!-- The type of listener: Marshal, Unmarshal or Both -->
            <xsd:element name="Type" maxOccurs="1" default="Both">
                <xsd:simpleType>
                    <xsd:restriction base="xsd:string">
                        <xsd:enumeration value="Marshal"/>
                        <xsd:enumeration value="Unmarshal"/>
                        <xsd:enumeration value="Both"/>
                    </xsd:restriction>
                </xsd:simpleType>
            </xsd:element>
        </xsd:sequence>
    </xsd:complexType>

</xsd:schema>
      
      

References

  1. Seven Steps to Test Automation Success
    Version from June 2001
    Bret Pettichord
    See http://www.io.com/~wazmo/papers/seven_steps.html
  2. JUnit Framework
    See http://www.junit.org/ and http://junit.sourceforge.net/junit3.8.1/index.html
  3. Castor XML
    Exolab Castor XML Team
    See http://castor.codehaus.org/
  4. Source Generator User Documentation
    Exolab Castor XML Team
    See http://castor.codehaus.org/SourceGeneratorUser.pdf
 
   
  
   
 


Copyright © 1999-2005 ExoLab Group, Intalio Inc., and Contributors. All rights reserved.
 
Java, EJB, JDBC, JNDI, JTA, Sun, Sun Microsystems are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and in other countries. XML, XML Schema, XSLT and related standards are trademarks or registered trademarks of MIT, INRIA, Keio or others, and a product of the World Wide Web Consortium. All other product names mentioned herein are trademarks of their respective owners.