Show last authors
1 {{box cssClass="floatinginfobox" title="**Contents**"}}
2 {{toc/}}
3 {{/box}}
4
5 = Concept =
6
7 This is about writing "unit" tests for code generated by the server-side for the "View" of the MVC model. Namely, it focuses on testing:
8
9 * wiki pages (##*.xml## files)
10 * velocity templates (##*.vm## files)
11
12 = Strategy =
13
14 Specifically the idea is to be able to write integration tests that use the real code except for all the environment parts (database queries, filesystem files, remote server calls, etc) which are mocked in the test. Whereas functional tests fully test everything in a running XWiki instance, View unit tests don't test the interactions with the environment, nor the execution in the browser (JS, CSS). On the other hand, View unit tests execute at a fraction of the cost of functional tests (3mn for a single functional test, < 1s for a View unit test, a few ms for a pure unit test in isolation).
15
16 The strategy is to write some functional tests since they are the only tests proving that a features works but to use View unit tests wherever possible to test the different paths of view resources (specifically the different paths taken by the scripts that execute inside of the view resources).
17
18 = Page Unit Testing =
19
20 The way those tests work is that the XML file representing the wiki pages are loaded from the filesystem into ##XWikiDocument## instances and a stubbed environment is defined so that ##XWikiDocument## can then be rendered in the desired syntax.
21
22 {{id name="common"/}}
23 To write such a test starting with the followng steps (common to both Page Unit Testing and Template Unit Testing):
24
25 * Make your POM depend on the ##org.xwiki.platform:xwiki-platform-test-page## module:(((
26 {{code language="xml"}}
27 <dependency>
28 <groupId>org.xwiki.platform</groupId>
29 <artifactId>xwiki-platform-test-page</artifactId>
30 <version>${project.version}</version>
31 <scope>test</scope>
32 </dependency>
33 {{/code}}
34 )))
35 * Write a Java test class that extends ##PageTest##
36 * Possibly add some extra component registration that you need through existing annotations (##*ComponentList## annotations) or through the custom ##ComponentList## annotation. Note that when extending ##PageTest## this automatically brings some base components registration (the list defined in ##PageComponentList## and ##ReferenceComponentList##). Example of other existing annotations:
37 ** ##XWikiSyntax20ComponentList##: XWiki Syntax 2.0-related components
38 ** ##XWikiSyntax21ComponentList##: XWiki Syntax 2.1-related components
39 ** ##XHTML10ComponentList##: XHTML 1.0-related components
40
41 Then:
42
43 * You then verify the rendering of a page by setting the output syntax you wish to have, the query parameters and then call ##renderPage()##. For example:(((
44 {{code language="java"}}
45 setOutputSyntax(Syntax.XHTML_1_0);
46 request.put("section", "Links");
47 request.put("xpage", "print");
48 ...
49 String result = renderPage(new DocumentReference("xwiki", "XWiki", "XWikiSyntax"));
50 assertTrue("...explanation if test fails", result.contains("...content that we wish to verify..."));
51 {{/code}}
52 )))
53 * If you need to have some other pages loaded from sources too (for example if the page you're rendering contains an include macro that loads another page), you'll use the(((
54 loadPage() API as in:##{{code language="java"}}loadPage(new DocumentReference("xwiki", "XWiki", "XWikiSyntaxLinks"));{{/code}}##
55 )))
56
57 Here's a full {{scm path="xwiki-platform-core/xwiki-platform-activitystream/xwiki-platform-activitystream-ui"}}example{{/scm}}:
58
59 {{code language="java"}}
60 @XWikiSyntax20ComponentList
61 @XHTML10ComponentList
62 public class WebRssTest extends PageTest
63 {
64 private ScriptQuery query;
65
66 @Before
67 public void setUp() throws Exception
68 {
69 setOutputSyntax(Syntax.PLAIN_1_0);
70 request.put("outputSyntax", "plain");
71 request.put("xpage", "plain");
72
73 QueryManagerScriptService qmss = mock(QueryManagerScriptService.class);
74 oldcore.getMocker().registerComponent(ScriptService.class, "query", qmss);
75 query = mock(ScriptQuery.class);
76 when(qmss.xwql("where 1=1 order by doc.date desc")).thenReturn(query);
77 }
78
79 @Test
80 public void webRssFiltersHiddenDocuments() throws Exception
81 {
82 // Render the page to test
83 renderPage(new DocumentReference("xwiki", "Main", "WebRss"));
84
85 // This is the real test!!
86 // We want to verify that the hidden document filter is called when executing the XWQL
87 // query to get the list of modified pages
88 verify(query).addFilter("hidden/document");
89 }
90
91 @Test
92 public void webRssDisplay() throws Exception
93 {
94 when(query.addFilter(anyString())).thenReturn(query);
95 when(query.setLimit(20)).thenReturn(query);
96 when(query.setOffset(0)).thenReturn(query);
97 when(query.execute()).thenReturn(Arrays.<Object>asList("Space1.Page1", "Space2.Page2"));
98
99 FeedPlugin plugin = new FeedPlugin("feed", FeedPlugin.class.getName(), context);
100 FeedPluginApi pluginApi = new FeedPluginApi(plugin, context);
101 when(xwiki.getPluginApi("feed", context)).thenReturn(pluginApi);
102
103 // Render the page to test
104 String xml = renderPage(new DocumentReference("xwiki", "Main", "WebRss"));
105
106 assertTrue(xml.contains("<title>activity.rss.feed.description</title>"));
107 assertTrue(xml.contains("<title>Page1</title>"));
108 assertTrue(xml.contains("<title>Page2</title>"));
109 }
110 }
111 {{/code}}
112
113 = Template Unit Testing =
114
115 To write such a test follow the [[common instruction>>WebHome||anchor="common"]].
116
117 Then:
118
119 * Add the dependencies on the JAR modules containing the templates needed. For example if you need to load directly or indirectly some template located in the ##xwiki-platform-web-templates## maven module (note that ##macros.vm## is loaded automatically by ##VelocityManager##), you'd write:(((
120 {{code language="xml"}}
121 <dependency>
122 <groupId>org.xwiki.platform</groupId>
123 <artifactId>xwiki-platform-web-templates</artifactId>
124 <version>${project.version}</version>
125 <scope>test</scope>
126 </dependency>
127 {{/code}}
128 )))
129 * You then use the ##TemplateManager## to call the template to test. For example:(((
130 {{code language="java"}}
131 public class MentionTemplateTest extends PageTest
132 {
133 @Test
134 void renderTemplateWhenXXX() throws Exception
135 {
136 // Add any mock for the environment here.
137
138 TemplateManager templateManager = oldcore.getMocker().getInstance(TemplateManager.class);
139 String result = templateManager.render("templates/mentions/mention.vm");
140
141 // Perform assertions here on the result.
142 }
143 {{/code}}
144 )))

Get Connected