Rendering Test Framework

Last modified by Vincent Massol on 2020/12/17 17:40

Allows you to write Syntax tests for your Parser and/or Renderer.

Adding a new Test Suite

Imagine that you've developed a new Syntax that is named xwiki/2.0. To test it you'd write the following unit test:

import org.xwiki.rendering.test.integration.junit5.RenderingTests;

@RenderingTestSuite.Scope(value = "xwiki20.specific")
public class XWiki20SpecificTest implements RenderingTests
{
}

If you're on XWiki <= 13.0RC1 you'd write the test as:

import org.junit.runner.RunWith;
import org.xwiki.rendering.test.integration.RenderingTestSuite;

@RunWith(RenderingTestSuite.class)
@RenderingTestSuite.Scope(value = "xwiki20.specific")
public class XWiki20SpecificTest
{
}

Running this will look for *.test files located in the classpath under the xwiki20/specific path (in term of sources files and Maven, this means putting your *.test files in src/main/resources/xwiki20/specific).

Adding Tests

Let's take an example to review the format of the *.test files. Imagine that we have a src/main/resources/xwiki20/specific/bold/bold2.test file with the following content:

.#-----------------------------------------------------
.input|xwiki/2.0
.#-----------------------------------------------------
This is **bold ** not bold** bold
.#-----------------------------------------------------
.expect|event/1.0
.#-----------------------------------------------------
beginDocument
beginParagraph
onWord [This]
onSpace
onWord [is]
onSpace
beginFormat [BOLD]
onWord [bold]
onSpace
endFormat [BOLD]
onSpace
onWord [not]
onSpace
onWord [bold]
beginFormat [BOLD]
onSpace
onWord [bold]
endFormat [BOLD]
endParagraph
endDocument
.#-----------------------------------------------------
.expect|xwiki/2.0
.#-----------------------------------------------------
This is **bold ** not bold** bold**

Let's understand what it does:

  • Comment lines start with .#.
  • Directives start with .. For example:
    • .input|xwiki/2.0 is an input directive that specifies the xwiki/2.0 syntax.
    • .expect|event/1.0 is an output directive that specifies the event/1.0 syntax (this is a special syntax that makes it easy to print XDOM blocks)
  • The RenderingTests code will do the following: for each input directive it can find, it uses the defined input syntax to find a matching Parser and it generates an XDOM from it. Then it looks for all defined output directives and for each one of them, it'll find a Renderer matching the output syntax and render the XDOM with it and verify that the result is the one defined.

If you execute the test suite above you'll get:

example1.png

The screenshots shows that 2 tests were executed:

  • Test 1: Using the xwiki/2.0 input content and verifying that the Parser generates an XDOM that when rendered with the event/1.0 syntax generates the content defined in the test
  • Test 2: Using the xwiki/2.0 input content and verifying that the Parser generates an XDOM that when rendered with the xwiki/2.0 syntax generates the content defined in the test

Note that when we have an input content similar to the output content (we want to verify a full round trip, using both Parser and Renderer for a given syntax) we can use the .inputexpect shortcut notation, as in:

.#-----------------------------------------------------
.inputexpect|xwiki/2.0
.#-----------------------------------------------------
This is **bold ** not bold** bold
.#-----------------------------------------------------
.expect|event/1.0
.#-----------------------------------------------------
beginDocument
beginParagraph
onWord [This]
onSpace
onWord [is]
onSpace
beginFormat [BOLD]
onWord [bold]
onSpace
endFormat [BOLD]
onSpace
onWord [not]
onSpace
onWord [bold]
beginFormat [BOLD]
onSpace
onWord [bold]
endFormat [BOLD]
endParagraph
endDocument

Advanced

Pattern

If you wish your test suite to only execute a single test (to debug only this test for example), you can add the pattern value in the Scope annotation. For example the following will only execute the /bold2.test test:

@RenderingTests.Scope(value = "xwiki20.specific", pattern = "bold2.test")
public class XWiki20SpecificTest implements RenderingTests
{
}

If you're on XWiki <= 13.0RC1 you'd write the test as:

@RunWith(RenderingTestSuite.class)
@RenderingTestSuite.Scope(value = "xwiki20.specific", pattern = "bold2.test")
public class XWiki20SpecificTest
{
}

Transformations

You may want to execute Macro Transformations on the parsed XDOM (to generate a modified XDOM) before doing the verification with the expected output. This can be achieved by adding the .runTransformations directive, as in:

.runTransformations
.#-----------------------------------------------------
.input|xwiki/2.1
.# Test the macro in inline mode
.#-----------------------------------------------------
This is inline {{example parameter="hello"/}}
.#-----------------------------------------------------
.expect|xhtml/1.0
.#-----------------------------------------------------
<p>This is inline hello</p>
.#-----------------------------------------------------
.expect|event/1.0
.#-----------------------------------------------------
beginDocument
beginParagraph
onWord [This]
onSpace
onWord [is]
onSpace
onWord [inline]
onSpace
beginMacroMarkerInline [example] [parameter=hello]
onWord [hello]
endMacroMarkerInline [example] [parameter=hello]
endParagraph
endDocument

Since XWiki 9.11.4/10.2RC1 You can specify the exact list of transformations to execute using the synta:

.runTransformations:hint1,...,hintN

For example to run only the Macro transformation:

.runTransformations:macro

When not specified, all transformations found in the context class loader are executed.

Mocking

You may wish to perform some initialization of mocks before running the tests. This can be achieved by adding a method annotated with @RenderingTestSuite.Initialized and accepting a MockitoComponentManager parameter, as in the following example:

@RenderingTests.Scope("wiki")
@AllComponents
public class WikiIntegrationTests implements RenderingTests
{
   @RenderingTests.Initialized
   public void initialize(MockitoComponentManager componentManager) throws Exception
   {
        componentManager.registerComponent(MockWikiModel.getComponentDescriptor());

       // Add InterWiki Definition for links28 test
       DefaultRenderingConfiguration renderingConfiguration =
           (DefaultRenderingConfiguration) componentManager.getInstance(RenderingConfiguration.class);
        renderingConfiguration.addInterWikiDefinition("knownalias", "http://server/common/url/");
   }
}

If you're on XWiki <= 13.0RC1 you'd write the test as:

@RunWith(RenderingTestSuite.class)
@RenderingTestSuite.Scope("wiki")
@AllComponents
public class WikiIntegrationTests
{
   @RenderingTestSuite.Initialized
   public void initialize(MockitoComponentManager componentManager) throws Exception
   {
        componentManager.registerComponent(MockWikiModel.getComponentDescriptor());

       // Add InterWiki Definition for links28 test
       DefaultRenderingConfiguration renderingConfiguration =
           (DefaultRenderingConfiguration) componentManager.getInstance(RenderingConfiguration.class);
        renderingConfiguration.addInterWikiDefinition("knownalias", "http://server/common/url/");
   }
}

Also notice the usage of the @AllComponents annotation which tells the Rendering Test Site to automatically register all XWiki Components found in the ClassLoader used to load this test. You could also use the @ComponentList({...}) annotation to only register some components. For example:

@ComponentList({
    DefaultBeanManager.class,
    DefaultConverterManager.class,
    EnumConverter.class,
    ConvertUtilsConverter.class
})
  • Powered by XWiki 15.10.8-node1. Hosted and managed by XWiki SAS

Get Connected