You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Mark Leicester <ma...@metering.co.nz> on 2003/08/04 15:57:19 UTC

An approach to unit testing in Cocoon / MIDIGenerator

Hi,

I'd like to get your comments on the approach to Unit testing I have used in
developing my Cocoon components. I think that this approach can be extended
to provide unit tests for all Cocoon components - and I'd like to help write
these. For example, as Cocoon depends on many other projects it would be
great to have a suite of tests that we can automatically run to test new
versions of these other components. We could take the guesswork out of
testing new versions of Xalan/XSLTC!

Anyhow, attached is a .zip file with an eclipse project containing:

1. My MIDIGenerator and the unit testing TestMIDIGenerator.

2. Some cocoon helper classes I have created to help with unit testing.
These classes implement various cocoon environment interfaces. In
org.apache.cocoon.test.components there is a CocoonComponentManager, and in
org.apache.cocoon.test.environment there is a CocoonRequest, a CocoonSession
and a CocoonSourceResolver. These classes exist to make life easier when you
are instantiating and setting up components intended for use in Cocoon
outside of the Cocoon environment (e.g. in the Eclipse debug environment).
For example, the CocoonRequest allows you to pass request parameters as if
from the browser. 

3. A sample MIDI file (Bach's Prelude No.1 in C, BWV846a nicely sequenced by
B.R.Guillaud and available from http://www.classicalarchives.com/bach.html),
and the same file converted into XMidi. See http://www.palserv.com/XMidi/
for Peter Loeb's original java code to convert MIDI to XML, now modified to
be SAX-based, and a little about XMidi.

The Eclipse project dependencies are:

$COCOON_LIB/logkit-1.2.jar
$COCOON_LIB/excalibur-sourceresolve-2003071
$COCOON_LIB/excalibur-pool-1.2.jar
$COCOON_LIB/excalibur-logger-1.0.1.jar
$COCOON_LIB/avalon-framework-4.1.4.jar
$COCOON_LIB/excalibur-xmlutil-20030520.jar
$COCOON_LIB/excalibur-instrument-1.0.jar
$COCOON_LIB/excalibur-component-1.1.jar
$COCOON_LIB/cocoon-2.1rc2-dev.jar
$JUNIT_JAR
$JDOM_JAR

To give anyone not familiar with JUnit testing some code to look at, listed
below is the source for the TestMIDIGenerator. It also illustrates the use
of my cocoon helper classes. Actually, I have only one JUnit test in there -
that is: assertTrue(generator != null); but there could be many more to
provide a stronger indication that the tested code has worked (counting
generated nodes, checksumming the XML output string for a known value etc.).
Testing provides a nice way to create a set of fixed and repeatable tests
that can be executed automatically. Eclipse has built-in support for it. See
http://www.junit.org/index.htm for more on JUnit. Note also the use of JDOM
for pithy processing of XML (see http://www.jdom.org).

===========================================================================

package org.apache.cocoon.test.generation;

//import java.io.FileOutputStream;
import java.util.Map;

import junit.framework.TestCase;

import org.apache.avalon.framework.context.DefaultContext;

import org.apache.avalon.framework.logger.ConsoleLogger;
//import org.apache.avalon.framework.logger.NullLogger;

import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.generation.MIDIGenerator;
import org.apache.cocoon.util.HashMap;
import org.jdom.input.SAXHandler;
import org.jdom.output.XMLOutputter;

import org.apache.cocoon.test.environment.CocoonRequest;
import org.apache.cocoon.test.environment.CocoonSourceResolver;

/**
 * @author Mark Leicester
 */
public class TestMIDIGenerator extends TestCase
{
  public void testGenerate() throws Exception
  {
    System.out.println("Testing generate()");

    MIDIGenerator generator = new MIDIGenerator();
    assertTrue(generator != null);

    // Cocoon 2.1 Set the logger to NULL
    // NullLogger logger = new NullLogger();
    // Cocoon 2.1 Set the logger to the console
    ConsoleLogger logger = new ConsoleLogger();
    generator.enableLogging(logger);

    // Globally parameterize the generator
    Parameters globalParameters = new Parameters();
    globalParameters.setParameter("verbose", "true");
    generator.parameterize(globalParameters);

    // Create src string: the URI for the midi file
    String src = "samples/midi/Prelude.mid";

    // Locally parameterize the generator
    Parameters localParameters = new Parameters();

    // Create the parameters (simulating a URL)
    Map map = new HashMap();
    CocoonRequest r = new CocoonRequest();
    // r.setParameter("name", "value");
    map.put(ObjectModelHelper.REQUEST_OBJECT, (Request) r);

    // Create the resolver needed to locate the schema file
    CocoonSourceResolver resolver = new CocoonSourceResolver();
    resolver.enableLogging(logger);
    // Set up the root directory for the source resolver
    // System.getProperty("user.dir") = project home directory
    DefaultContext context = new DefaultContext();
    context.put("context-dir", System.getProperty("user.dir"));
    resolver.contextualize(context);

    // Setup the generator
    generator.setup(resolver, map, src, localParameters);

    // Create the JDOM sax handler, and make it the content handler
    SAXHandler sh = new SAXHandler();
    generator.setContentHandler(sh);

    // Perform the generation
    generator.generate();

    // Get the JDOM document and write it to the System.out
    XMLOutputter xo = new XMLOutputter();
    xo.setNewlines(true);
    xo.output(sh.getDocument(), System.out);

    // Alternatively, get the JDOM document and write it to a file
    // FileOutputStream fileStream = new FileOutputStream("output.xmi");
    // xo.output(sh.getDocument(), fileStream);
    // fileStream.close();

    return;
  }

}

===========================================================================

If you think this is a good approach then please, treat this code as your
own! In due course I shall attempt to create a MIDI block (including the
test class itself), but I am thinking that the unit testing helper classes
would go into the cocoon project itself so that everyone can use them? As is
the case with the attached Eclipse project, I always keep the code to be
tested separate from the unit tests so that building .jars remains easy. I
usually put my java source into /src/java and my test code into /src/test.

I hope this approach will help us make cocoon even more robust!

Regards,
Mark


Re: Unit testing Cocoon (was: An approach to unit testing in Cocoon / MIDIGenerator)

Posted by Stephan Michels <st...@apache.org>.

On Tue, 5 Aug 2003, Mark Leicester wrote:

> Thank you for pointing me to your Cocoon unit testing framework[1] Stephan!
> I got a unit test for my MIDIGenerator going very quickly, and it *is* very
> easy to use. I was able to configure the .xtest file without too much
> trouble. Your testing framework is just what I wanted, and I'd like to help
> it gain maximum use and visibility.

Thank you, the orginal idea come from
http://strutstestcase.sourceforge.net/ .

> A few questions:
>
> 1. Do you intend to JAR up the testing classes (environment, mocks etc., but
> not the actual TestCases) in a way that they can be easily referenced from
> other non-core Cocoon projects?

Yes, can we do. Currently, there will be a jar created for all
core test classes, since they must be reachable by the
blocks.

> 2. How many people apart from yourself are actively working on your Cocoon
> test cases?

;-) Next question!

> 3. If I start on a documentation effort for what is there already, will I be
> overlapping with anyone else's work? If not, I will prepare some wiki docs
> outlining which TestCases have been written, and how they work.

Many thanks, these docs will be very helpful.

Stephan.


Unit testing Cocoon (was: An approach to unit testing in Cocoon / MIDIGenerator)

Posted by Mark Leicester <ma...@metering.co.nz>.
Thank you for pointing me to your Cocoon unit testing framework[1] Stephan!
I got a unit test for my MIDIGenerator going very quickly, and it *is* very
easy to use. I was able to configure the .xtest file without too much
trouble. Your testing framework is just what I wanted, and I'd like to help
it gain maximum use and visibility.

A few questions:

1. Do you intend to JAR up the testing classes (environment, mocks etc., but
not the actual TestCases) in a way that they can be easily referenced from
other non-core Cocoon projects?

2. How many people apart from yourself are actively working on your Cocoon
test cases?

3. If I start on a documentation effort for what is there already, will I be
overlapping with anyone else's work? If not, I will prepare some wiki docs
outlining which TestCases have been written, and how they work.

Mark

[1] Found in the /src/test/


Re: An approach to unit testing in Cocoon / MIDIGenerator

Posted by Stephan Michels <st...@apache.org>.


On Mon, 4 Aug 2003, Mark Leicester wrote:

> On 4/08/2003 15:15, "Stephan Michels" <st...@apache.org> wrote:
>
> > Have you take a look into
> > src/test/org/apache/cocoon/AbstractCompositeTestCase.java
>
> Heh, no I haven't seen this at all! Cool! Wow, this is the real thing! Is
> this quite new? I looked earlier this year and didn't see anything. I'll try
> it out immediately! Are there any docs for these unit testing classes yet? I
> looked quickly on the wiki and didn't find anything. If there aren't, I'm
> definitely keen to help!

Sorry, no docu. But I think it is pretty easy.

    public void testGenerator() {
        String src = "resource://input.xml";
        String result = "resource://result.xml";

        assertEqual(load(result),
                    generate("mygenerator", src, EMPTY_PARAMS));
    }

You can also test pipelines.

assertEqual(load(result),
            transform("mytransformer", src2, EMPTY_PARAMS,
	      generate("mygenerator", src, EMPTY_PARAMS)));

If you're using request paramters etc. you can easily change them by

    public void testRequestAction() {

        getRequest().setRequestURI("test.xml?abc=def&ghi=jkl");
        getRequest().setQueryString("abc=def&ghi=jkl");
        getRequest().setContextPath("servlet");
        getRequest().addParameter("abc", "def");

        Parameters parameters = new Parameters();
        parameters.setParameter("parameters", "true");

        Map result = act("request", null, parameters);

        assertNull("Test for parameter", (String)result.get("ghi"));
    }

The setup of the xtest file is a bit difficult, but using the
ExcaliburTestCase ensures that all lifecycle methods will be handled
correct.

Stephan.


Re: An approach to unit testing in Cocoon / MIDIGenerator

Posted by Mark Leicester <ma...@energyintellect.com>.
On 4/08/2003 15:15, "Stephan Michels" <st...@apache.org> wrote:

> Have you take a look into
> src/test/org/apache/cocoon/AbstractCompositeTestCase.java
Heh, no I haven't seen this at all! Cool! Wow, this is the real thing! Is
this quite new? I looked earlier this year and didn't see anything. I'll try
it out immediately! Are there any docs for these unit testing classes yet? I
looked quickly on the wiki and didn't find anything. If there aren't, I'm
definitely keen to help!

Mark


Re: An approach to unit testing in Cocoon / MIDIGenerator

Posted by Stephan Michels <st...@apache.org>.

On Mon, 4 Aug 2003, Mark Leicester wrote:

> Hi,
>
> I'd like to get your comments on the approach to Unit testing I have used in
> developing my Cocoon components. I think that this approach can be extended
> to provide unit tests for all Cocoon components - and I'd like to help write
> these. For example, as Cocoon depends on many other projects it would be
> great to have a suite of tests that we can automatically run to test new
> versions of these other components. We could take the guesswork out of
> testing new versions of Xalan/XSLTC!
>
> 2. Some cocoon helper classes I have created to help with unit testing.
> These classes implement various cocoon environment interfaces. In
> org.apache.cocoon.test.components there is a CocoonComponentManager, and in
> org.apache.cocoon.test.environment there is a CocoonRequest, a CocoonSession
> and a CocoonSourceResolver. These classes exist to make life easier when you
> are instantiating and setting up components intended for use in Cocoon
> outside of the Cocoon environment (e.g. in the Eclipse debug environment).

Have you take a look into
src/test/org/apache/cocoon/AbstractCompositeTestCase.java

It is an abstract testcase for testing action generator and transformers,
builds a almost complete enviroment with the mock classes within
src/test/org/apache/cocoon/environment/mock

Stephan.