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.
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.
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.
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
Other tests
Samples web application can be used to perform manual testing. Of course, contributions to automate these tests are welcome!