Dynamo Module for Cactus Integration Tests

Download DynaCactus.zip here

Copy of the README.txt

WHAT IS IT?

This is an ATG Dynamo module to allow you to use Jakarta's Cactus to test components. The components are tested directly while running inside Dynamo. This is important because:

- Dynamo is a lot to do with configuration, not just code
- It allows you to perform integration tests, testing a component, an repository specification and a database schema working together.
- It allows you to perform tests which are hard to simulate from a web front end, and will certainly allow you to run the tests faster.


HOW DO I INSTALL?

1. Expand the DynaCactus.zip into your Dynamo home directory, so that you have a directory such as C:\ATG\Dynamo5.6.1\DynaCactus.

2. Grab a copy of Jakarta's Cactus and put it in the directory DynaCactus/lib/cactus. The module is configured to work with Cactus 1.6.1

3. If you use a version other than Cactus 1.6.1, you will need to edit the file DynaCactus/META-INF/MANIFEST.MF to point to the correct names of the libraries. 

4. If you use a version other than Cactus 1.6.1 and you are using Eclipse, you will need to edit the file DynaCactus/.classpath to point to the correct names of the libraries.


HOW DO I USE?

The DynaCactus is a separate Dynamo module. You could choose to include it in your own module, but as you will probably not want to ship your test code to the live servers, I suggest you create a new Dynamo module. For example, if the module you want to test is called MyProj, then create a new module called MyProjTest, that depends on the modules MyProj and DynaCactus. See Dynamo documentation about how to create modules.

In your test module, you will need to create the Cactus test cases. Here's a simple test I create for all my projects:

	package nucleus.atg.dynamo;
	
	import atg.service.dynamo.Configuration;
	import atg.servlet.DynamoHttpServletRequest;
	
	import org.apache.cactus.server.dynamo.DynamoTestCase;
	
	public class ConfigurationTest extends DynamoTestCase {
	
	    public void testVersion() throws Exception {
	        Configuration configuration = (Configuration) getDynamoRequest().resolveName("/atg/dynamo/Configuration");
	        assertEquals("Must have correct version of Dynamo", "Dynamo 5.6.1", configuration.getVersion());
	    }
	
	}

Notes:

1. This test case makes sure we're running the correct version of Dynamo for my project.

2. The package name can be anything you like, but I start with nucleus, then the path name of the component. Note that we're testing components here -- actual object instances -- and not classes like normal jUnit tests. In this case we're testing the component /atg/dynamo/Configuration, so the test case class is nucleus.atg.dynamo.ConfigurationTest. By putting everything inside the nucleus package, we ensure we don't have name space clashes with class based jUnit tests.

3. We inherit from DynaCactus' DynamoTestCase that inherits from Cactus' ServletTestCase that inherits from jUnit's TestCase.

4. The first line of the test is used to get out Configuration component, based on the current request: the getDynamoRequest() method returns an instance of atg.servlet.DynamoHttpServletRequest. Because we work from a request, we don't care if components are request, session or globally scoped. Typically, you will put this in an overridden setUp() method, see example below.

5. The assertEquals() method checks we're running the correct version of Dynamo.

You run the Cactus tests in the usual way, see the Cactus manuals. Don't forget to set cactus system property cactus.contextURL.


TESTING A TYPICAL COMPONENT

Typically, one of my tests looks like this:

	package nucleus.myproj.webcommerce;
	
	import org.apache.cactus.server.dynamo.DynamoTestCase;
	
	import com.myproj.MyComponentClass;
	
	public class MyComponentTest extends DynamoTestCase {
	
	    private MyComponentClass mService;
	
	    protected void setUp() throws Exception {
	        super.setUp();
	        
	        mService = (MyComponentClass) getDynamoRequest().resolveName("/myproj/webcommerce/MyComponent");
	    }
	    
	    public void testSetUp() throws Exception {
	        assertNotNull("Service was created", mService);
	        assertNotNull("Property size set", mService.getSize());
	        assertFalse("Service has listeners", mService.getActionListeners().isEmpty());
	    }
	    
	    public void testSimple() throws Exception {
	        // perform a simple test
	        // ...
	    }
	    
	    public void testMoreComplex() throws Exception {
	        // perform a more complex test
	        // ...
	    }
	    
	    public void testVeryComplex() throws Exception {
	        // perform a very complex test
	        // ...
	    }
	    
	}

NOTES:

1. I use the same naming convention, putting everything in nucleus package, and the name of the test is based on the component's name, not the component's class' name.

2. I get the component in the setUp() method, as all tests in a TestCase should use the same component.

3. The first test I write checks that the component has been created correctly inside Dynamo. Typically this sort of testing is done inside the component's doStartService() method, which would mean that it's run every time a component starts up (think about request scoped components). I find it better to do it here, as we get a big red bar if there are configuration errors.

4. I then perform my test specific to this component, in increasing order of complexity. Therefore, if something simple is broken, this will be the first test to fail.


OTHER TESTING STRATEGIES

I use DynaCactus as the middle of three levels of testing:

1. Unit Testing using jUnit, jMock and MockObjects -- Everything that I can test in isolation, outside of Dynamo, I do so. Not only does it give you a finer control over the testing process, it also isolates you from bugs elsewhere. Moreover, if you use Test Driven Development, most of you complex testing should be performed at this level. I use the jMock library to create mock objects, and in the past I have use the Dynamo parts of MockObjects for deeper testing.

2. Integration Testing using DynaCactus -- As so much of Dynamo's power comes from configuration, and select components together, I use DynaCactus to test this. For example, in a previous project I tested all possible and erroneous combinations of creating new users: this tested my component, my configuration of the Profile repository and the database schema.

3. Web Front End testing using Jiffie -- This is a testing environment based around controlling Internet Explorer from Java. Therefore, you can put web testing inside jUnit tests. I have also contributed to this project.


USING IN ECLIPSE

-- Not yet written


FUTURE ENHANCEMENTS

1. Use a Dynamic ClassLoader for the test cases, so that you can re-write your tests without restarting Dynamo.

2. Test on more versions of Dynamo. Currently only tested under Dynamo 5.6.1.

3. Write an example using one of Dynamo's existing demo applications.

4. Put this project somewhere sensible, like in Cactus, or on SourceForge.


LICENSE

I am still considering the license issue. For the moment I ask you not to redistribute, and to pass any changes or enhancements you make to the DynaCactus module back to me. Because DynaCactus is a discreet module, this should not effect any licensing issues you have.


FOR MORE INFORMATION

See the xpatg group on http://groups.yahoo.com/group/xpatg/


REFERENCES

ATG Dynamo
	http://www.atg.com

jUnit
	http://www.junit.org

jMock
	http://www.jmock.org

MockObjects
	http://www.mockobjects.com
	
Jiffie
	http://www.sf.net/projects/jiffie

Extreme Programming in ATG
	http://groups.yahoo.com/group/xpatg/

AUTHOR
- Piran Montford, 12 Nov 2004