cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Upayavira>
Subject [RT] Unit testing and CocoonUnit
Date Sat, 01 Nov 2003 17:21:47 GMT
Dear All,

After reading of Steve K's efforts on this list, and reading "Extreme 
Programming Java Cookbook", I would like to propose a Cocoon pipeline 
unit testing framework, based arount HTTPUnit, XMLUnit and the CocoonBean.

HTTPUnit provides a user agent for engaging in 'conversations' with a 
web server, and allows you to test the responses at any stage within 
this conversation. E.g. is there a form called 'cart' on the HTML page; 
is an error message 'Email address required' displayed within the page.

HTTPUnit, to my mind, provides some valuable functionality, but given 
the nature of the web, it is primarily aimed at functional testing 
rather than unit testing. It tests whether the end result of a process 
is correct, but not what happened to get there.

XMLUnit extends JUnit to give XML aware assertions, which can compare 
such things as "<node/>" and "<node></node>" and correctly identify 
these as being the same.

CocoonUnit will be based upon, and if possible extend, HTTPUnit. A 'web 
conversation' will take place in the same way as it would with HTTPUnit. 
The only difference is that you would be able to get at the XML from 
each stage of a pipeline with response.getPipelineXML(pipelinePos); . 
Then, using XMLUnit, you can test to ensure that the XML at any relevant 
stage in the pipeline is as you would want.

public class MyXMLTestCase extends XMLTestCase {
    public MyXMLTestCase(String name) {
    public void testForEquality() throws Exception {
       CocoonConversation cocoonConversation =  new CocoonConversation();
       CocoonRequest request = new 
       CocoonResponse response = webConversation.getResponse(request);

       String generatorXML = response.getPipelineXML(0);
       String transformedXML = response.getPipelineXML(1);

       assertXpathExists("//para[contains(.,'Cocoon')]", generatorXML);
       assertXpathNotExists("//para[contains(.,'Active Server Pages')]", 

       // further tests on the transformedXML

This class would then be executed as any normal JUnit test case, e.g. 
direct from your IDE, or as a part of your build process via an Ant 
build script.

CocoonUnit would use the CocoonBean to pass requests to Cocoon. The bean 
would prepare an Environment (maybe even an HTTPEnvironment), and would 
place an empty ArrayList into the object model with a key of UNIT_TEST_XML.

Then, in AbstractProcessingPipeline, there are two process() methods, 
each of which call connectPipeline(). Immediately before these calls to 
connectPipeline, a test would be done for the UNIT_TEST_XML object in 
the object model. If it is present, the transformer ArrayLists (all four 
of them), would be modified. At the beginning, and then between each 
transformer, a DOMGatheringTransformer will be inserted. This 
DOMGatheringTransformer simply builds a DOM object and adds it to the 
UNIT_TEST_XML ArrayList stored in the object model. and then forwards 
its SAX events unmodified to the next stage in the pipeline.

Once a resource has been generated, the CocoonBean can extract this 
UNIT_TEST_XML ArrayList and pass it back to the CocoonResponse, so that 
its XML DOMs can be available via response.getPipelineXML();

This so far seems relatively straightforward. The most complicated part 
to implement, as I see it, will be extending HTTPUnit to interface with 
Cocoon instead of its own methods for getting web resources. I have only 
had a cursory look at HTTPUnit, but it does seem to have a reasonably 
active mailing list that I hope could help me. Should this part prove to 
be too complex, I would write my own (limited) version of HTTPUnit. It 
seems that you can either use HTTP to get pages, or use its own 
'simulated servlet container' to run servlets without a real container. 
I could potentially extend or amend either of these to use the CocoonBean.

The CocoonBean may need some extending to enable it to create one Cocoon 
instance at the beginning of the testing process, and to then share that 
instance across all subsequent tests (whether simultaneous or 
sequential). Otherwise, each test would need to initialise and dispose 
the CocoonBeanm which would be a waste of resources.

Extension Possibilities
Once the above works, it would not be hard to allow this method to test 
specific sections of a pipeline, by supplying the input, as well as 
testing the output:

       CocoonConversation cocoonConversation =  new CocoonConversation();
       CocoonRequest request = new 
       request.setPipelineXML(1, "<xml>.....</xml>");
       CocoonResponse response = webConversation.getResponse(request);
       String transformedXML = response.getPipelineXML(2);

       assertXpathExists("//para[contains(.,'Cocoon')]", transformedXML);

The above sets the input to the second stage of the pipeline, which the 
DOMGatheringTransformer (now a UnitTestTransformer) uses instead of the 
incoming SAX stream.

Unit testing helps to provide reliable code. Unit testing in a Web 
environment is not always straightforward as your 'units' aren't always 
clearly defined. With Cocoon, however, stages in a pipeline can be 
considered to be 'units', and therefore could be tested independently of 
each other. Adding a CocoonUnit to the Cocoon codebase would further 
extend Cocoon's ability to be used in substantial web environments where 
automated testing is crucial to success.

What do you all think?


View raw message