Apache » Cocoon »

  Apache Cocoon
   homepage

Apache Cocoon

Apache Cocoon Tests

Overview of testing procedures

Since Apache Cocoon uses Apache Maven automatic unit testing is very tighly integrated with build process. We also use Continuum to ensure that Apache Cocoon can run properly on your particular computing platform and that the components do function properly.

You can build upon this infrastructure to add your own tests, and to ensure that development work proceeds smoothly. The tests for each module (block) are located in the src/test/ directory.

JUnit Tests

If you run mvn install JUnit test cases are executed automatically and build procedure will fail if any test fails.  JUnit test cases cover:

  • testing various pipeline/sitemap components (including trasformers, matcher, generators, sources, etc.)
  • testing the methods for getting platform-dependent filesystem pathnames; etc.
Note: It is important to pay attention to class'es package and name because test's configuration setup seekes for files that follow convention. In order to set up all needed components and execute test as expected you need to follow proper directory structure that is shown in an example below.

How to add more JUnit tests for Avalon-managed class

As there is already a nice junit framework available, it is not that difficult to add junit tests for any class. The process will be explained step-by-step getting as an example org.apache.cocoon.template.JXTemplateGenerator class from cocoon-template-impl module.

Component configuration

You must create JXTemplateGeneratorTestCase.xtest file and put it at src/test/resources/og/apache/cocoon/template. The file will contain configuration for components that tested generator needs to work with. Example file may look like this:
<testcase>
    <roles>
        <role name="org.apache.cocoon.generation.GeneratorSelector" shorthand="generators"
              default-class="org.apache.cocoon.core.container.DefaultServiceSelector"/>
        <role name="org.apache.excalibur.store.Store/TransientStore" shorthand="store" default-class="org.apache.excalibur.store.impl.MemoryStore"/>
        <role name="org.apache.cocoon.template.expression.StringTemplateParserSelector" shorthand="string-template-parsers"
              default-class="org.apache.cocoon.core.container.DefaultServiceSelector"/>
    </roles>
    <components>
        <generators logger="test">
            <component-instance class="org.apache.cocoon.template.JXTemplateGenerator" name="jx"/>
        </generators>
        <component role="org.apache.cocoon.template.script.ScriptManager" class="org.apache.cocoon.template.script.DefaultScriptManager"/>
        <component role="org.apache.cocoon.template.script.InstructionFactory" class="org.apache.cocoon.template.script.DefaultInstructionFactory"/>
        <string-template-parsers>
          <component-instance class="org.apache.cocoon.template.expression.JXTGStringTemplateParser" name="jxtg"/>
          <component-instance class="org.apache.cocoon.template.expression.DefaultStringTemplateParser" name="default"/>
        </string-template-parsers>
    </components>
</testcase>

As you can see, several components and generator itself are set up.

Java test-case

Now you must create JXTemplateGeneratorTestCase.java file and put it at src/test/java/org/apache/cocoon/template. The class should extend org.apache.cocoon.SitemapComponentTestCase from cocoon-core module so the Avalon's ServiceManager is set up properly and you can use lots of helper methods. Next step is writing actual testing methods, example method would look like:

public void testGenerate() throws Exception {
  String inputURI = docBase + "generate.xml";

  assertEqual(load(inputURI), generate(JX, inputURI, EMPTY_PARAMS));
}

This simple method tests if generator reads simple input file (generate.xml) and emits all SAX events properly.

Note: It useful to check SitemapComponentTestCase and CocoonTestCase source code (or Javadocs) to find out what methods are already provided for your convenience.
For example, very convient method for use is lookup() that enables you to look up for a new instance of Avalon component properly initialized according to Avalon's lifecycle management.

Execute the test

As stated earlier Maven will execute all tests every time the build is performed so if you want to check if everything is working you can go to root directory of cocoon-template-impl and execute:

mvn clean install

As the output you should get something like this:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.apache.cocoon.template.jxtg.JXTemplateGeneratorTestCase
[DEBUG] XMLizer: Default parser is 'org.apache.excalibur.xml.sax.SAXParser'.
[DEBUG] Resolved to systemID : resource://org/apache/cocoon/template/jxtg/generate.xml
[DEBUG] Creating source object for resource://org/apache/cocoon/template/jxtg/generate.xml
[DEBUG] JaxpParser: validating: false, namespace-prefixes: false, reuse parser: true, stop on warning: true, stop on recoverable-error: true, saxParserFactory: javax.xml.parsers.SAXParserFactory, documentBuilderFactory: javax.xml.parsers.DocumentBuilderFactory, resolver hint: null
[DEBUG] Releasing source object for resource://org/apache/cocoon/template/jxtg/generate.xml
[DEBUG] Resolving 'resource://org/apache/cocoon/template/jxtg/generate.xml' with base 'null' in context 'file:/home/grek/asf/cocoon-trunk/blocks/cocoon-template/cocoon-template-impl/'
[DEBUG] Resolved to systemID : resource://org/apache/cocoon/template/jxtg/generate.xml
[DEBUG] Creating source object for resource://org/apache/cocoon/template/jxtg/generate.xml
[DEBUG] Releasing source object for resource://org/apache/cocoon/template/jxtg/generate.xml
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.524 sec

Which indicates that everything went just fine.

How to add more JUnit tests for Spring-managed class

I suggest to read a section above describing how to write tests for Avalon components because I will show only focus on differences in particular steps. This time, we will examine how to write test for classes handling expression evaluation from cocoon-expression-language-impl. Let's assume we create test named "Expression".

Components configuration

Instead of creating *.xtest file you must create *.spring.xml file to configure Spring beans. First we create ExpressionTestCase.spring.xml file with contents like this:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
  
  <import resource="classpath:META-INF/cocoon/spring/DefaultExpressionFactory.xml"/>
  <import resource="classpath:META-INF/cocoon/spring/JavaScriptCompiler.xml"/>
  <import resource="classpath:META-INF/cocoon/spring/JexlCompiler.xml"/>
  <import resource="classpath:META-INF/cocoon/spring/JXPathCompiler.xml"/>
  
</beans>

As you can see we only import other configuration files that are, in a fact, ordinar configuration files used in development. This approach is much cleaner than one used for Avalon class testing because you have to configure particular bean only one time and reuse this configuration while testing.

Java test-case

As writing test-case class for Spring bean is not much different from writing corresponding class for Avalon component I'm not going to describe it in detail.

The only difference that I would like to point out is how you should get an instance of Spring bean. Instead of using lookup method you should use getFactoryBean().getBean() method.

Take a look at this method as an example:

public void testFactoryJexl() throws ExpressionException {
  ExpressionFactory factory = (ExpressionFactory) this.getBeanFactory().getBean(ExpressionFactory.ROLE);
  assertNotNull("Test lookup of expression factory", factory);

  Expression expression = factory.getExpression("jexl", "1+2");
  assertNotNull("Test expression compilation", expression);

  assertEquals(new Long(3), expression.evaluate(new ExpressionContext()));
}

Execute the test

Tests for Spring beans should be executed exactly the same way that tests for Avalon components are executed so I point you to instructions above.

htmlunit Tests

Fixme: I do not know what is the status of htmlunit tests in trunk, JIRA issue COCOON-1488 contains more information

Other tests

Samples web application can be used to perform manual testing. Of course, contributions to automate these tests are welcome!