Upayavira --

This all looks great. I've also been hacking at this problem and have a working solution that does not involve any open pipeline surgery or triple-pipeline-bypasses. It is a bit of a hack and I do believe your solution is much more appropriate in the long term, however, maybe what I've done will give you some more ideas.

Originally I was using the CocoonBean to test pipelines, but I had some new pipelines that needed access to HTTP headers and cookies -- and I could not find a way to pass them in using the interfaces provided by the bean. So I did the following:

- I extended the ExcaliburTestCase to create a CocoonTestCase. In my new class I copied the initalize() and getClassPath() methods from the CocoonWrapper and modified it all enough so on JUnit setUp() I could instantiate an instance of Cocoon and stick it in a member variable. The reason I extended ExcaliburTestCase is that I have several Avalon components that my application uses that I also use to set up the test cases.

- To send a request to Cocoon, I create an HttpEnvironment object using mock servlet objects -- specifically the objects from http://strutstestcase.sourceforge.net/. When I get the request back, I parse it into XML and use the XMLUnit style asserts on it. Here is what the code looks like:

----

// set up the mock objects

ServletContextSimulator sctx = new ServletContextSimulator();
HttpContext hc = new HttpContext((ServletContext) sctx);
HttpServletRequestSimulator req = new HttpServletRequestSimulator(sctx);
HttpServletResponseSimulator res = new HttpServletResponseSimulator();

// set up the HTTP request

req.setHeader("Accept", text/xml,application/xml");
req.setHeader("Accept-Language", "en");
req.setParameterValue("cocoon-view", new String [] {"content"});

// output goes to baos

ByteArrayOutputStream baos = new ByteArrayOutputStream();
res.setOutputStream(out);

// set up HttpEnvironment to get the uri "foo/bar"

HttpEnvironment env = new HttpEnvironment(
        "foo/bar",
        "path/to/webapp",
        (HttpServletRequest) req,
        (HttpServletResponse) res,
        (ServletContext) sctx,
        hc,
        "",
        "");
env.enableLogging(new LogKitLogger(getLogger()));

// call process() on the cocoon member variable

boolean rv = cocoon.process(env);
baos.flush();

// parse the response into XML

SAXParser parser = (SAXParser) this.manager.lookup(SAXParser.ROLE);
DOMBuilder builder = new DOMBuilder();
parser.parse(new InputSource(
    new ByteArrayInputStream(baos.toByteArray())),
    new WhitespaceFilter(builder),
    builder);
Document xml = builder.getDocument();
this.manager.release((Component) parser);

// test the xml

assertXPathTrue(xml, "/blah");

----

This has worked pretty well so far. I think extending the ExaliburTestCase and using mock servlet objects might be better than extedning HTTPUnit since it gives us more flexibility and more access to the raw Coccon request/response.

Some other things I've investigated on the way:

- Jakarta Cactus (http://jakarta.apache.org/cactus/) -- This takes a similar approach by setting up a mock servlet environment to test your servlets in. However, it seemed way to big and complicated to do what I thought would be very simple. Also, I think there is a lot to be gained by unit testing at the pipeline level as you suggest, rather than treating Cocoon like just another servlet.

- In my search for a mock implementation of the servlet classes, I came along MockObjects (http://www.mockobjects.com). They have mock objects for much of the Java API, however, their approach didn't really fit into what I was trying to do. Basically, you are supposed to pre-program the mock objects to expect certain method calls (e.g. getHeader should be called with such and such parameters, then getSession should be called, etc). Since I just wanted mock objects good enough to masquerade as a servlet container and get the output from Cocoon, this was not very helpful. However, perhaps a similar methodology could be adapted where you could pass in the expected XML for each pipeline step -- I think you had this idea in our previous exchanges.

And finally, on a somewhat unrelated subject, one thing that I've always wanted Cocoon to do may be possible if support for collecting the XML at each pipeline step is added. To aid in debugging, I think it would be very helpful to switch on some kind of debug mode, that would cause a trace of what pipeline steps where executed and the state of the XML at each step to be printed out at the bottom of each page you output to the browser. This way it is easy for a developer to see the path though the pipelines the request took, as well as a snapshot of the XML each step of the way.

cheers,
-steve




Reply via email to