WUnit quick start
In this complete and runnable tutorial, you'll learn how to use in a very basic Web application with forms, files to upload and a bit of AJAX. You'll also learn how to act on the server internals.
The full documentation is available here.
- Download and install
- The Web application to test : an image gallery
- Running the gallery application
- Designing the test suite
- Testing the welcome page
- Testing the gallery page
- Testing the upload page
- Testing the delete page
- Testing the global kinematic
- Running the whole test suite
- Repairing errors
- Testing without server emulator
- And now ?
Download and install
You must have Java 1.5 or higher installed in your computer. If you want to run the Web application supplied in this tutorial you don't need a servlet engine, however you're not compelled to run it since the Web application to test is described enough with some snapshots in the next sections.
Download the full binary distribution that contains , , and the engine.
Unzip reflex-0.4.0-full-bin.zip in the directory of your choice, say file:///path/to/reflex/. Hereafter, commands are launched from the directory where has been unzipped.
The Web application to test : an image gallery
The Web application to test contains few Web pages described hereafter ; it consist on inviting the user to upload images on the server and display them on a gallery page. It consists on four pages :
- the welcome page, that contains links to the other pages below
- a form that can upload files and set them a name
- a display page, that displays images uploaded
- a delete page for removing images from the gallery
Server-side, the images uploaded are stored on a temporary directory on the disk with a reference in the user session. On the delete page, images are selectable with an AJAX autocompleter that send queries to the server.
Web application details
This Web application is made with and is runnable with , like of course any non- Web applications. If you have to test servlets you'll be able to act on server objects as well.
You can check all the files of the image gallery application in the [REFLEX_HOME]/doc/tutorial/wunit/webapp directory. The source code of the activlet contains only about 100 lines of code. You can examine it here.
Screenshots
The Welcome page :
![[www]](./img/ico-web.png)
Welcome to your image gallery !
What do you want to do ?
The Upload page :
The Gallery page :
![[www]](./img/ico-web.png)
The Delete page :
Running the gallery application
This step is optional, you can skip this section.
Open a console and at the prompt, type the following commands from the home directory
(note that the
(line cut) icon means that you MUST NOT insert a line break) :
$ java -cp reflex-0.4.0.jar:xunit-0.4.0.jar winstone.Launcher--httpPort=9999 --webroot=doc/tutorial/wunit/webapp/
Then run a Web browser : http://localhost:9999/ and play with the Web application. Keep the console open while using the Web browser and to stop the server, simply hit CTRL-C on the console.
You can of course change the default port (at the same time on the command line and on the URI of the browser) if it is already busy on your system.
Designing the test suite
We will run the Web application within the server emulator, so that you don't need a servlet container such as Tomcat (or like Winstone used above). That also will allow to act directly on the objects stored in the session.
We want to ensure that when filling the form and clicking to the links we do get the expected results. For this purpose we mimick the behaviour of a human behind its browser with ; once done, all the test suite can be submitted again and again without human intervention ; in a real-world Web application, hundreds of tests would be run similarly at once in order to check that the application still works after an upgrade : this is the purpose of regression tests.
In this tutorial, we are going to write our test incrementally. We intend to test individually each page and then test a complete scenario. Each test will introduce a specific feature :
- basics : GET a page, make a launcher, examine the test report
- act on sessions server side
- fill a form
- get an XML page, send Javascript events (keyboard and click)
This should cover rather well the functional of our Web application, client side and server side.
Testing the welcome page
In (as well as in ), markups either stand for operations or are litterals. We use active tags from several modules to build our test suite : some from such as <wunit:conversation>, <wunit:GET>, <wunit:submit>, or later <wunit:fill-form>, others from the XML Control Language such as <xcl:active-sheet>, <xcl:parse-html> or <xcl:param>, and others from such as <xunit:test-case>, <xunit:assert-string-equals> or <xunit:assert-node-equals>. Everything that appear in curly braces "{" and "}" (and displayed in bold in the following listings) is an XPath expression that can also contain materials supplied by a module, such as the io:file() XPath function, and the $sys:out and $wunit:frame XPath variables. You can also refer to the index of active materials.
The first test aims to check that everything works fine. The comments are explaining what we do :
[doc/tutorial/wunit/test-suite/1-welcome-page.xcl]
<?xml version="1.0" encoding="iso-8859-1"?>
<!--this is the root of the script ; it serves to declare modules that are used (namespace declarations act like library import instructions)--> <xcl:active-sheet xmlns:xcl="http://ns.inria.org/active-tags/xcl" xmlns:sys="http://ns.inria.org/active-tags/sys" xmlns:xunit="http://reflex.gforge.inria.fr/xunit.html" xmlns:wunit="http://reflex.gforge.inria.fr/wunit.html"> <!--set the boundary of the test case--> <xunit:test-case name="report/1-gallery-welcome" label="[Web] Welcome page"> <!--start to discuss with the servlet emulator--> <wunit:conversation application="../webapp/WEB-INF/web.xml" uri="http://www.example.com/"> <!--get the welcome page hosted in our server emulator--> <wunit:GET url="http://www.example.com/"/> <!--do we have it ? we ask to the $wunit:frame predefined property what is the HTTP response code--> <xunit:assert-number-equals result="{ value( $wunit:frame/@wunit:response-code ) }" expected="200"/> <!--is it an HTML page ?--> <xunit:assert-string-equals result="{ string( $wunit:frame/@wunit:mime-type ) }" expected="text/html"/> <!--parse the static welcome page from the file system...--> <xcl:parse-html source="../webapp/index.html" name="expected" elems-name="lower"/> <!--...and compare it with those returned by the server. $wunit:document is a predefined property that refers to the DOM of the HTML document of the current page--> <xunit:assert-node-equals result="{ $wunit:document }" expected="{ $expected }"/> </wunit:conversation> </xunit:test-case> </xcl:active-sheet>
Since we will have other tests, we are creating a launcher that will run the whole test suite and build an HTML report ; right now, it is only running the single test we made :
[doc/tutorial/wunit/test-suite/run-all-tests.xcl]
<?xml version="1.0" encoding="iso-8859-1"?>
<!--this is a launcher--> <xcl:active-sheet xmlns:xcl="http://ns.inria.org/active-tags/xcl" xmlns:io="http://ns.inria.org/active-tags/io" xmlns:exp="http://ns.inria.org/active-tags/exp" xmlns:xunit="http://reflex.gforge.inria.fr/xunit.html"> <!--invoke our tests--> <exp:invoke processor="1-welcome-page.xcl"/> <!--[[[add more tests later here]]]--> <!--merge all the reports in a single one--> <xunit:merge-reports name="Summary of Web-Gallery tests" source="{ io:file( 'report/' ) }"
output="{ io:file( 'gallery-err.xml' ) }"/> <!--create an HTML version of the report--> <xcl:transform source="gallery-err.xml" output="gallery-err.html"
stylesheet="res:///org/inria/ns/reflex/util/xunit/html-report.xsl"/> <!--res:///... indicates that the XSLT stylesheet is bundled in a jar file--> </xcl:active-sheet>
Now, let's run the launcher that will invoke our test and build an HTML report
(remember that the
(line cut) icon means that you MUST NOT insert a line break):
$ java -cp reflex-0.4.0.jar:xunit-0.4.0.jarorg.inria.ns.reflex.ReflexCLI run doc/tutorial/wunit/test-suite/run-all-tests.xcl
In the standard output you can see a short summary :
. Test suite : Summary of Web-Gallery tests Test cases : 1 (79) Errors : 0 (0) Failures : 0 (0) Files : 1
It indicates that a single test was run, and in parenthesis indicates the number of atomic tests. It is somewhat big because we ask to check that the 2 HTML documents (those in our file system and those returned by the server) were equals, and every element, attribute, and text content were compared.
If you open the [doc/tutorial/wunit/test-suite/gallery-err.html] file in a Web navigator, you can examine the HTML report ; if we had errors, the Web report would be more detailed than the summary displayed in the standard output.
![[www]](./img/ico-web.png)
XUnit report
Skip Test name | Tests | Errors | Failure | |
|---|---|---|---|---|
0 Summary of Web-Gallery tests | 1 (79) | 0 (0) | 0 (0) | |
| 1/1 | [Web] Welcome page | 79 | 0 | 0 |
Voilà !
Testing the gallery page
In this second test, we are testing the gallery page. Unfortunately, it is empty (let's check that it is empty !). So, we are going to cheat a little bit by creating directly session objects server side and checking that they are brought back to the client. XPath is used to extract relevant parts from the HTML page.
Of course, that implies to have a knowledge of the internal of the Web application that runs server-side.
[doc/tutorial/wunit/test-suite/2-gallery-page.xcl]
<?xml version="1.0" encoding="iso-8859-1"?>
<xcl:active-sheet xmlns:xcl="http://ns.inria.org/active-tags/xcl" xmlns:io="http://ns.inria.org/active-tags/io" xmlns:sys="http://ns.inria.org/active-tags/sys" xmlns:xunit="http://reflex.gforge.inria.fr/xunit.html" xmlns:wunit="http://reflex.gforge.inria.fr/wunit.html"> <!--set the boundary of the test case--> <xunit:test-case name="report/2-gallery-images" label="[Web] Gallery page"> <!--start to discuss with the servlet emulator--> <wunit:conversation application="../webapp/WEB-INF/web.xml" uri="http://www.example.com/"> <!--get the gallery page--> <wunit:GET url="http://www.example.com/gallery.html"/> <!--check that the gallery is empty we should have at the end of the HTML page : <P>Empty gallery.</P>--> <xunit:assert-string-equals result="{ $wunit:document//p[last()] }" expected="Empty gallery."/> <xunit:assert-number-equals result="{ value( $wunit:frame/@wunit:response-code ) }" expected="200"/> <xunit:assert-string-equals result="{ string( $wunit:frame/@wunit:mime-type ) }" expected="text/html"/> <!--store directly some objects in the current session server-side (objects are stored as attributes) ; the objects stored are images from the file system--> <xcl:attribute name="item1" value="{ io:file( '../img/xml-10.png' ) }"
referent="{ $wunit:session }"/> <xcl:attribute name="item2" value="{ io:file( '../img/xml2006-logo.png' ) }"
referent="{ $wunit:session }"/> <!--get again the gallery page ; this time it shouldn't be empty--> <wunit:GET url="http://www.example.com/gallery.html"/> <xunit:assert-number-equals result="{ value( $wunit:frame/@wunit:response-code ) }" expected="200"/> <xunit:assert-string-equals result="{ string( $wunit:frame/@wunit:mime-type ) }" expected="text/html"/> <!--write an HTML trace to sysout--> <xcl:transform source="{ $wunit:document }" output="{ $sys:out }"/> <!--we should have 2 rows--> <xunit:assert-number-equals result="{ count( $wunit:document//tr ) }" expected="2"/> <!--first row--> <xunit:assert-string-equals result="{ $wunit:document//tr[1]/td[1] }" expected="item1"/> <xunit:assert-string-equals result="{ $wunit:document//tr[1]/td[2]/img/@src }" expected="images/item1"/> <!--second row--> <xunit:assert-string-equals result="{ $wunit:document//tr[2]/td[1] }" expected="item2"/> <xunit:assert-string-equals result="{ $wunit:document//tr[2]/td[2]/img/@src }" expected="images/item2"/> </wunit:conversation> </xunit:test-case> </xcl:active-sheet>
To run it, just append in the launcher (tutorial/wunit/run-all-tests.xcl) the new test to the active sheets to invoke :
<exp:invoke processor="1-welcome-page.xcl"/> <exp:invoke processor="2-gallery-page.xcl"/>
Testing the upload page
There is a form to fill client side with 2 fields, one is a file to upload. After the upload, we check the message in the response page, and ensure that the file reference has been stored in the object session.
The message in the response page looks like this :
[doc/tutorial/wunit/test-suite/3-upload-page.xcl]
<?xml version="1.0" encoding="iso-8859-1"?>
<xcl:active-sheet xmlns:xcl="http://ns.inria.org/active-tags/xcl" xmlns:io="http://ns.inria.org/active-tags/io" xmlns:sys="http://ns.inria.org/active-tags/sys" xmlns:xunit="http://reflex.gforge.inria.fr/xunit.html" xmlns:wunit="http://reflex.gforge.inria.fr/wunit.html"> <!--set the boundary of the test case--> <xunit:test-case name="report/3-gallery-upload" label="[Web] Upload page"> <!--start to discuss with the servlet emulator--> <wunit:conversation application="../webapp/WEB-INF/web.xml" uri="http://www.example.com/"> <!--get the upload page--> <wunit:GET url="http://www.example.com/upload.html"/> <xunit:assert-number-equals result="{ value( $wunit:frame/@wunit:response-code ) }" expected="200"/> <xunit:assert-string-equals result="{ string( $wunit:frame/@wunit:mime-type ) }" expected="text/html"/> <!--fill the HTML form and POST it to the server--> <wunit:fill-form form="{ $wunit:document//form[@name='upload'] }"> <!--the text input is a string--> <xcl:param name="imageName" value="test1"/> <!--the file to upload, just give it a file--> <xcl:param name="imageFile" value="{ io:file( '../img/xml-10.png' ) }"/> </wunit:fill-form> <!--write an HTML trace to sysout--> <xcl:transform source="{ $wunit:document }" output="{ $sys:out }"/> <!--check the message in the response page sent by the server--> <xunit:assert-string-equals result="{ normalize-space( $wunit:document//body/div[1] ) }"
expected="xml-10.png uploaded."/> <!--check that the session object was created ; it contains a reference to a file stored in the server ; we just check the name of the file--> <xunit:assert-string-equals result="{ name( value( $wunit:session/@test1 ) ) }" expected="xml-10.png"/> </wunit:conversation> </xunit:test-case> </xcl:active-sheet>
Note that :
- The component behind <wunit:fill-form> works with subelements (<xcl:param>) that are independant of . The parameters used here are those that appear in the HTML form.
- We are using the standard XPath function normalize-space() in order to trim the spaces before and after the relevant information to check.
- In the last active tag, the value() function allows to get the value bound to the attribute referred (like with PSVI when a typed data is bound after augmentation). Here, the value bound is a file reference.
Like previously, append in the launcher the new test :
<exp:invoke processor="1-welcome-page.xcl"/> <exp:invoke processor="2-gallery-page.xcl"/> <exp:invoke processor="3-upload-page.xcl"/>
Testing the delete page
There are several stuff to test in this page :
- the request sent by the autocompleter
- the delete function when the form is submitted
- the AJAX behaviour
Like previously, we are bypassing the global functionning by setting some file references in the current session.
[doc/tutorial/wunit/test-suite/4-delete-page.xcl]
<?xml version="1.0" encoding="iso-8859-1"?>
<xcl:active-sheet xmlns:xcl="http://ns.inria.org/active-tags/xcl" xmlns:io="http://ns.inria.org/active-tags/io" xmlns:sys="http://ns.inria.org/active-tags/sys" xmlns:xunit="http://reflex.gforge.inria.fr/xunit.html" xmlns:wunit="http://reflex.gforge.inria.fr/wunit.html"> <!--start to discuss with the servlet emulator--> <wunit:conversation application="../webapp/WEB-INF/web.xml" uri="http://www.example.com/"> <!-- ********************* XML Test ********************* --> <xunit:test-case name="report/4a-gallery-delete-ajax" label="[Web] Delete page : AJAX"> <!--store directly some objects in the current session server-side--> <xcl:attribute name="item2" value="{ io:file( '../img/xml2006-logo.png' ) }"
referent="{ $wunit:session }"/> <xcl:attribute name="item1" value="{ io:file( '../img/xml-10.png' ) }"
referent="{ $wunit:session }"/> <xcl:attribute name="another" value="{ io:file( '../img/xml2006-logo.png' ) }"
referent="{ $wunit:session }"/> <!--get the autocompleter : we'll get the objects which name starts with "it" --> <wunit:GET url="http://www.example.com/images.xml?imageName=it"/> <xunit:assert-number-equals result="{ value( $wunit:frame/@wunit:response-code ) }" expected="200"/> <xunit:assert-string-equals result="{ string( $wunit:frame/@wunit:mime-type ) }" expected="application/xml"/> <!--create an inline HTML fragment of the result expected ; whitespaces are important !!! the result produced by the server doesn't contain whitespaces --> <xcl:document name="expected"><ul><li>item1</li><li>item2</li></ul></xcl:document> <!--compare the fragment get with those expected--> <xunit:assert-node-equals result="{ $wunit:document }" expected="{ $expected }"/> </xunit:test-case> <!-- ********************* Delete page ********************* --> <xunit:test-case name="report/4b-gallery-delete-form" label="[Web] Delete page : form"> <!--get the delete page--> <wunit:GET url="http://www.example.com/delete.html"/> <xunit:assert-number-equals result="{ value( $wunit:frame/@wunit:response-code ) }" expected="200"/> <xunit:assert-string-equals result="{ string( $wunit:frame/@wunit:mime-type ) }" expected="text/html"/> <!--fill the HTML form and submit it to the server--> <wunit:fill-form form="{ $wunit:document//form[@name='delete'] }"> <!--the text input is a string--> <xcl:param name="imageName" value="item1"/> </wunit:fill-form> <!--write an HTML trace to sysout--> <xcl:transform source="{ $wunit:document }" output="{ $sys:out }"/> <!--check the message in the response page sent by the server--> <xunit:assert-string-equals result="{ normalize-space( $wunit:document//body/div[1] ) }"
expected="xml-10.png deleted."/> <!--check that the session object was deleted, and that other session objects were preserved--> <xunit:assert-false result="{ name( value( $wunit:session/@item1 ) ) }"/> <xunit:assert-string-equals result="{ name( value( $wunit:session/@item2 ) ) }" expected="xml2006-logo.png"/> <xunit:assert-string-equals result="{ name( value( $wunit:session/@another ) ) }"
expected="xml2006-logo.png"/> </xunit:test-case> <!-- ********************* Javascript (Autocompleter Test) ********************* --> <xunit:test-case name="report/4c-gallery-delete-js" label="[Web] Delete page : Javascript"> <!--restore in the session the item that we have just deleted--> <xcl:attribute name="item1" value="{ io:file( '../img/xml-10.png' ) }"
referent="{ $wunit:session }"/> <!--what we have so far : -the delete page loaded -3 items stored in the session server side we intend to send events that will involve the Javascript autocompleter--> <!--fill the HTML form WITHOUT submitting it to the server--> <wunit:fill-form form="{ $wunit:document//form[@name='delete'] }" submit="no"> <!--fill partially the input text in order to get from the server the image names that start with "it" "item1" and "item2" will be candidate--> <xcl:param name="imageName" value="it"/> </wunit:fill-form> <!--let the client having enough time to display the result sent by the server (the autocompleter accept a delay parameter to set with Javascript) we are waiting 1000 ms--> <xcl:sleep value="1000"/> <!--click on the second item of the list--> <wunit:click target="{ $wunit:document//div[@id='list']/ul/li[2] }"/> <!--submit the form as-is : as we have clicked on the 2nd <li>, the input field should have been its value set to "item2"--> <wunit:fill-form form="{ $wunit:document//form[@name='delete'] }"/> <!--check the message in the response page sent by the server--> <xunit:assert-string-equals result="{ normalize-space( $wunit:document//body/div[1] ) }"
expected="xml2006-logo.png deleted."/> <!--check that the session object was deleted, and that other session objects were preserved--> <xunit:assert-false result="{ name( value( $wunit:session/@item2 ) ) }"/> <xunit:assert-string-equals result="{ name( value( $wunit:session/@item1 ) ) }" expected="xml-10.png"/> <xunit:assert-string-equals result="{ name( value( $wunit:session/@another ) ) }"
expected="xml2006-logo.png"/> </xunit:test-case> </wunit:conversation> </xcl:active-sheet>
Once again, we append in the launcher the new test :
<exp:invoke processor="1-welcome-page.xcl"/> <exp:invoke processor="2-gallery-page.xcl"/> <exp:invoke processor="3-upload-page.xcl"/> <exp:invoke processor="4-delete-page.xcl"/>
Testing the global kinematic
Here is a real scenario that a human could perform. But can process it thousand times without complaining.
[doc/tutorial/wunit/test-suite/5-scenario.xcl]
<?xml version="1.0" encoding="iso-8859-1"?>
<!--this is the root of the script ; it serves to declare modules that are used (act like a library import instruction)--> <xcl:active-sheet xmlns:xcl="http://ns.inria.org/active-tags/xcl" xmlns:io="http://ns.inria.org/active-tags/io" xmlns:sys="http://ns.inria.org/active-tags/sys" xmlns:xunit="http://reflex.gforge.inria.fr/xunit.html" xmlns:wunit="http://reflex.gforge.inria.fr/wunit.html"> <!--scenario : -get the "upload" page -upload a file -upload a file -click on the link "gallery" -click on the link "delete" -delete an item -click on the link "gallery"--> <!--set the boundary of the test case--> <xunit:test-case name="report/5-gallery-scenario" label="[Web] Scenario"> <!--start to discuss with the servlet emulator--> <wunit:conversation application="../webapp/WEB-INF/web.xml" uri="http://www.example.com/"> <!--get the welcome page hosted in our server emulator--> <wunit:GET url="http://www.example.com/upload.html"/> <!--do we have it ? we ask to the $wunit:frame predefined property what is the HTTP response code--> <xunit:assert-number-equals result="{ value( $wunit:frame/@wunit:response-code ) }" expected="200"/> <!--is it an HTML page ?--> <xunit:assert-string-equals result="{ string( $wunit:frame/@wunit:mime-type ) }" expected="text/html"/> <!--fill the HTML form and POST it to the server--> <wunit:fill-form form="{ $wunit:document//form[@name='upload'] }"> <!--the text input is a string--> <xcl:param name="imageName" value="test1"/> <!--the file to upload, just give it a file--> <xcl:param name="imageFile" value="{ io:file( '../img/xml-10.png' ) }"/> </wunit:fill-form> <!--check the message in the response page sent by the server--> <xunit:assert-string-equals result="{ normalize-space( $wunit:document//body/div[1] ) }"
expected="xml-10.png uploaded."/> <!--fill the HTML form and POST it to the server--> <wunit:fill-form form="{ $wunit:document//form[@name='upload'] }"> <xcl:param name="imageName" value="test2"/> <xcl:param name="imageFile" value="{ io:file( '../img/xml2006-logo.png' ) }"/> </wunit:fill-form> <!--check the message in the response page sent by the server--> <xunit:assert-string-equals result="{ normalize-space( $wunit:document//body/div[1] ) }"
expected="xml2006-logo.png uploaded."/> <!--click on the link "gallery"--> <wunit:click target="{ $wunit:document//a[@href='gallery.html'] }"/> <!--write an HTML trace to sysout--> <xcl:transform source="{ $wunit:document }" output="{ $sys:out }"/> <!--we should have 2 rows--> <xunit:assert-number-equals result="{ count( $wunit:document//tr ) }" expected="2"/> <!--first row--> <xunit:assert-string-equals result="{ $wunit:document//tr[1]/td[1] }" expected="test1"/> <xunit:assert-string-equals result="{ $wunit:document//tr[1]/td[2]/img/@src }" expected="images/test1"/> <!--second row--> <xunit:assert-string-equals result="{ $wunit:document//tr[2]/td[1] }" expected="test2"/> <xunit:assert-string-equals result="{ $wunit:document//tr[2]/td[2]/img/@src }" expected="images/test2"/> <!--click on the link "delete"--> <wunit:click target="{ $wunit:document//a[@href='delete.html'] }"/> <wunit:fill-form form="{ $wunit:document//form[@name='delete'] }"> <xcl:param name="imageName" value="test1"/> </wunit:fill-form> <!--click on the link "gallery"--> <wunit:submit event="click" target="{ $wunit:document//a[@href='gallery.html'] }"/> <!--write an HTML trace to sysout--> <xcl:transform source="{ $wunit:document }" output="{ $sys:out }"/> <!--we should have 1 row--> <xunit:assert-number-equals result="{ count( $wunit:document//tr ) }" expected="1"/> <!--first row--> <xunit:assert-string-equals result="{ $wunit:document//tr[1]/td[1] }" expected="test2"/> <xunit:assert-string-equals result="{ $wunit:document//tr[1]/td[2]/img/@src }" expected="images/test2"/> </wunit:conversation> </xunit:test-case> </xcl:active-sheet>
As usual, the new test is appended to the suite :
<exp:invoke processor="1-welcome-page.xcl"/> <exp:invoke processor="2-gallery-page.xcl"/> <exp:invoke processor="3-upload-page.xcl"/> <exp:invoke processor="4-delete-page.xcl"/> <exp:invoke processor="5-scenario.xcl"/>
Running the whole test suite
We now have a bunch of tests. If you run all the tests at once, you get the following results :
....... Test suite : Summary of Web-Gallery tests Test cases : 7 (135) Errors : 0 (0) Failures : 0 (0) Files : 7
In the HTML report [doc/tutorial/wunit/test-suite/gallery-err.html] you can notice that the XSLT traces we wrote during the test to the standard output have been captured.
Repairing errors
So far, we have tested a well-designed Web application with no errors regarding the result expected. Let's introduce a (fictious) error in the Web application... We change in the Web application what is returned when the autocompleter is involved.
The HTML error report shows clearly that 3 errors were found in some tests. The details of the former (click on [Display errors] below) indicate that the server wrongly sends an <ol> element instead of the <ul> element expected by the autocompleter. The 2 latter errors are consequences : they fail because we weren't able to get the right element and delete the image in our gallery. In a normal situation, a developer would identify the assertion that cause the error, localize the piece of code to correct in the Web application source and rerun the test suite.
You can experiment yourself what happens when you inject other errors in the Web application ; you can act directly on the source by editing the file [doc/tutorial/wunit/webapp/WEB-INF/active-sheet.web] : around line 47, you can change the local name of the element like we did, or add an unexpected attribute or set the XHTML namespace for example.
![[www]](./img/ico-web.png)
XUnit report
Skip Test name | Tests | Errors | Failure | |
|---|---|---|---|---|
0 Summary of Web-Gallery tests | 7 (124) | 2 (3) | 0 (0) | |
| 1/7 | [Web] Welcome page | 79 | 0 | 0 |
| 2/7 | [Web] Gallery page | 10 | 0 | 0 |
| 3/7 | [Web] Upload page | 4 | 0 | 0 |
| 4/7 | [Web] Delete page : AJAX | 9 | 1 | 0 |
| 5/7 | [Web] Delete page : form | 6 | 0 | 0 |
| 6/7 | [Web] Delete page : Javascript | 4 | 2 | 0 |
| 7/7 | [Web] Scenario | 12 | 0 | 0 |
Testing without server emulator
Our test suite works pretty well, but what would it be if our Web application wasn't made with servlets ? We would be able to test it anyway but with less control on server-side components like we did. Any test where session objects were authoritatively stored can't be run. The tests that remain are the welcome page and the scenario.
In the code of those tests, the differences are that the @application attribute of the <wunit:conversation> elements have been removed and that the URLs submitted have to point to a real Web server where the application to test has been deployed. The following source code is almost the same as the previous one :
[doc/tutorial/wunit/test-suite-with-server/5-scenario.xcl]
<?xml version="1.0" encoding="iso-8859-1"?>
<!--this is the root of the script ; it serves to declare modules that are used (act like a library import instruction)--> <xcl:active-sheet xmlns:xcl="http://ns.inria.org/active-tags/xcl" xmlns:io="http://ns.inria.org/active-tags/io" xmlns:sys="http://ns.inria.org/active-tags/sys" xmlns:xunit="http://reflex.gforge.inria.fr/xunit.html" xmlns:wunit="http://reflex.gforge.inria.fr/wunit.html"> <!--scenario : -get the "upload" page -upload a file -upload a file -click on the link "gallery" -click on the link "delete" -delete an item -click on the link "gallery"--> <!--set the boundary of the test case--> <xunit:test-case name="report/5-gallery-scenario" label="[Web] Scenario"> <!--start to discuss with the server--> <wunit:conversation> <!--get the upload page ; the server have to be started before--> <wunit:submit method="GET" url="http://localhost:9999/upload.html"/> <!--do we have it ? we ask to the $wunit:frame predefined property what is the HTTP response code--> <xunit:assert-string-equals result="{ string( $wunit:frame/@wunit:response-code ) }" expected="200"/> <!--is it an HTML page ?--> <xunit:assert-string-equals result="{ string( $wunit:frame/@wunit:mime-type ) }" expected="text/html"/> <!--fill the HTML form and POST it to the server--> <wunit:fill-form form="{ $wunit:document//FORM[@name='upload'] }"> <!--the text input is a string--> <xcl:param name="imageName" value="test1"/> <!--the file to upload, just give it a file--> <xcl:param name="imageFile" value="{ io:file( '../img/xml-10.png' ) }"/> </wunit:fill-form> <!--check the message in the response page sent by the server--> <xunit:assert-string-equals result="{ normalize-space( $wunit:document//BODY/DIV[1] ) }"
expected="xml-10.png uploaded."/> <!--fill the HTML form and POST it to the server--> <wunit:fill-form form="{ $wunit:document//FORM[@name='upload'] }"> <xcl:param name="imageName" value="test2"/> <xcl:param name="imageFile" value="{ io:file( '../img/xml2006-logo.png' ) }"/> </wunit:fill-form> <!--check the message in the response page sent by the server--> <xunit:assert-string-equals result="{ normalize-space( $wunit:document//BODY/DIV[1] ) }"
expected="xml2006-logo.png uploaded."/> <!--click on the link "gallery"--> <wunit:submit event="click" target="{ $wunit:document//A[@href='gallery.html'] }"/> <!--write an HTML trace to sysout--> <xcl:transform source="{ $wunit:document }" output="{ $sys:out }"/> <!--we should have 2 rows--> <xunit:assert-number-equals result="{ count( $wunit:document//TR ) }" expected="2"/> <!--first row--> <xunit:assert-string-equals result="{ $wunit:document//TR[1]/TD[1] }" expected="test1"/> <xunit:assert-string-equals result="{ $wunit:document//TR[1]/TD[2]/IMG/@src }" expected="images/test1"/> <!--second row--> <xunit:assert-string-equals result="{ $wunit:document//TR[2]/TD[1] }" expected="test2"/> <xunit:assert-string-equals result="{ $wunit:document//TR[2]/TD[2]/IMG/@src }" expected="images/test2"/> <!--click on the link "delete"--> <wunit:submit event="click" target="{ $wunit:document//A[@href='delete.html'] }"/> <wunit:fill-form form="{ $wunit:document//FORM[@name='delete'] }"> <xcl:param name="imageName" value="test1"/> </wunit:fill-form> <!--click on the link "gallery"--> <wunit:submit event="click" target="{ $wunit:document//A[@href='gallery.html'] }"/> <!--write an HTML trace to sysout--> <xcl:transform source="{ $wunit:document }" output="{ $sys:out }"/> <!--we should have 1 row--> <xunit:assert-number-equals result="{ count( $wunit:document//TR ) }" expected="1"/> <!--first row--> <xunit:assert-string-equals result="{ $wunit:document//TR[1]/TD[1] }" expected="test2"/> <xunit:assert-string-equals result="{ $wunit:document//TR[1]/TD[2]/IMG/@src }" expected="images/test2"/> </wunit:conversation> </xunit:test-case> </xcl:active-sheet>
You can launch them in the same way but this time you have to run the Web server :
$ java -cp reflex-0.4.0.jar:xunit-0.4.0.jar winstone.Launcher--httpPort=9999 --webroot=doc/tutorial/wunit/webapp/
And in a separate console :
$ java -cp reflex-0.4.0.jar:xunit-0.4.0.jarorg.inria.ns.reflex.ReflexCLI run doc/tutorial/wunit/test-suite-with-server/run-tests.xcl
And now ?
Want more ?
Check the WUnit full documentation for the complete reference of the module and other tips, and the XUnit cookbook.




