Writing tests
Steps
Testing the Confluence modules is extra important
It is very important to test your modifications and have good coverage.
- Confluence to XWiki syntax conversion is a difficult and fragile process. A conversion bug might not be immediately noticeable, and a bug will most certainly cause content loss and content loss might be difficult or impossible to fix, especially if noticed months after an import. Importing is a one shot process. Fixing bugs will not fix content that's already imported. For this reason, we want to avoid conversion bugs, and especially regressions
- We are dealing with a lot of undocumented stuff. Tests are sometimes the best thing we have handy to determine how things work. They are de facto references, even if we also make up a lot of things in tests
The upside is that writing tests for your macro converter happens to be usually about the easiest and laziest way to check that your code works. It's way easier to write a test and run it than to get or craft a confluence package and run it on the wiki.
Testing Confluence XML
This includes all the XML package parsing process, the filter stream generation and macro converters.
Most things are tested through the filter integration test framework (class org.xwiki.filter.test.integration.FilterTestSuite). They are run from the org.xwiki.contrib.confluence.filter.IntegrationTests class which does some setup including some convenient mocks. It looks for tests in .test files in the confluence-xml/src/test/resources/confluencexml folder. These files give the expected result in Filter XML format, representing a generated wiki, and input parameters, including specific parameters you want to test or use (some of them allow you to skip some stuff to reduce the test size), and more importantly the source. The source is a zip file or a folder containing a confluence export: an entities.xml file, maybe an exportDescriptor.properties file and maybe an attachments folder.
To create a new test, copy a suitable .test file, the accompanying source folder, and edit the content. For macro converters, a good start is the emoji.test file, which is small and has one document.
.#------------------------------------------------------------------------------
.expect|filter+xml
.# Content conversions
.#------------------------------------------------------------------------------
<wikiSpace name="TestSpace">
<wikiDocument name="WebHome">
<wikiDocumentLocale>
<wikiDocumentRevision revision="1">
<p>
<parameters>
<entry>
<string>title</string>
<string>TestSpace</string>
</entry>
<entry>
<string>syntax</string>
<org.xwiki.rendering.syntax.Syntax>
<type>
<name>XWiki</name>
<id>xwiki</id>
<variants class="empty-list"/>
</type>
<version>2.1</version>
</org.xwiki.rendering.syntax.Syntax>
</entry>
<entry>
<string>content</string>
<string>{{children/}}</string>
</entry>
</parameters>
</p>
</wikiDocumentRevision>
</wikiDocumentLocale>
</wikiDocument>
<wikiSpace name="TestContent">
<wikiDocument name="WebHome">
<wikiDocumentLocale>
<wikiDocumentRevision revision="10">
<p>
<parameters>
<entry>
<string>title</string>
<string>TestContent</string>
</entry>
<entry>
<string>content</string>
<string>My emoticon:(replaced because xwiki.org doesn't handle emojis)
[...]
Two keycap 2 emojis: (replaced because xwiki.org doesn't handle emojis) (replaced because xwiki.org doesn't handle emojis)</string>
</entry>
<entry>
<string>syntax</string>
<org.xwiki.rendering.syntax.Syntax>
<type>
<name>XWiki</name>
<id>xwiki</id>
<variants class="empty-list"/>
</type>
<version>2.1</version>
</org.xwiki.rendering.syntax.Syntax>
</entry>
</parameters>
</p>
</wikiDocumentRevision>
</wikiDocumentLocale>
</wikiDocument>
</wikiSpace>
</wikiSpace>
.#------------------------------------------------------------------------------
.input|confluence+xml
.configuration.storeConfluenceDetailsEnabled=false
.configuration.source=emoji
.configuration.unprefixedMacros=code
.#------------------------------------------------------------------------------If you are testing a macro converter, your test should obviously contain a page that uses the macro you are implementing, ideally with several combinations of macro parameters if applicable.
Tips
- Name your test file wisely
- You can add a few words at the beginning of the text after the .expect line to describe what you are testing
- Ideally, one test per feature is nice, but testing something by adding to an existing test is better than no test at all. It is good enough if the intent is clear. It will also run a bit faster. Debugging a failing test might be trickier though. In doubt, create a new, small, test.
- Beware: if your test is not well formed, it might not run at all and that's silent. Make sure your test run
- Use an IDE to develop your tests. It's way way way more convenient than waiting for maven to build everything, reach your test and produce diffs that are difficult to work with.
- Start with an empty document content in your .test file, let the test fail but produce the expected content, and when you are happy, paste the expected content in the test file.
- You can start by running only your new test by editing the IntegrationTests.java class by editing
@FilterTestSuite.Scope(value = "confluencexml"/*, pattern = "confluence80tags.test"*/). You uncomment the pattern parameter and write the name of your test there.- Do not forget to revert your change and do not commit them. Your IDE might provide a convenient feature for this. If you forget, Jacoco will complain when running the quality checks because this breaks the coverage.
- Do run all the tests after your are done with yours, which helps with item 1 by the way. The macro you implement could be in another test package, or the modification you are doing might affect other tests
- It might be that the thing you are fixing or implementing is already present in a test package. In this case, you could be lazy and not create a whole new test and use what's existing if what's existing happens to test everything that needs to be tested
Testing Confluence XHTML
When you work on the XHTML parser, you have several ways to test your changes. Spend some time in confluence-xhtml/src/test/resources/ to see what's there. Some tests are about generated wikimodel events, some are about generated XWiki syntax. Then, advises from the previous section generally apply.
Notes:
- You can test your code from a Confluence XML test. But it's best to write an XHTML test in confluence-xhtml/src/test/resources/.
- Confluence XML macro converters do not run there, so don't expect macros to be converter
- Some modifications in Confluence XHTML usually affects tests in Confluence XML, so you will probably to adjust tests in Confluence XML (as well), especially if you are fixing something in XHTML specifically because it affects a specific macro converter.
- Because of last item and because life is not perfect, many "Confluence XHTML tests" do live in Confluence XML tests in practice. If you do this too much, Jacoco will likely complain about the coverage though.