Getting Started - xspec/xspec GitHub Wiki
This page demonstrates how to get started with XSpec. It runs through a tutorial that tests an XSLT stylesheet with XSpec. The examples are in the tutorial
directory.
Make sure that XSpec is installed correctly by running the help message at the end of the installation process:
The tutorial directory contains an sample of XSLT stylesheet escape-for-regex.xsl
to test and its sample XSpec test suite escape-for-regex.xspec
.
The stylesheet file to test is specified in the @stylesheet
attribute at the beginning of the XSpec file:
<x:description xmlns:x="http://www.jenitennison.com/xslt/xspec"
xmlns:functx="http://www.functx.com"
stylesheet="escape-for-regex.xsl">
Navigate to your XSpec directory (e.g. ~/xspec/
for Mac/Linux or C:\xspec\
for Windows) and run the XSpec test suite with this command:
For Mac/Linux:
bin/xspec.sh tutorial/escape-for-regex.xspec
For Windows:
bin\xspec.bat tutorial\escape-for-regex.xspec
Note that you invoke the XSpec script against the XSpec test file (*.xspec
), not the stylesheet file (*.xsl
).
The output in the shell should be similar to this:
Creating XSpec Directory at tutorial/xspec...
Creating Test Stylesheet...
Checking for deprecated Saxon versions: Passed
Running Tests...
Testing with SAXON HE 10.9
No escaping
Must not be escaped at all
Test simple patterns
..When encountering parentheses
escape them.
..When encountering a whitespace character class
escape the backslash
result should have one more character than source
When processing a list of phrases
All phrase elements should remain
Strings should be escaped and status attributes should be added
FAILED
Formatting Report...
passed: 5 / pending: 0 / failed: 1 / total: 6
Report available at tutorial/xspec/escape-for-regex-result.html
Done.
If everything worked, there should be a new xspec
subdirectory in ~/xspec/tutorial
(or C:\xspec\tutorial
). It contains three files generated by XSpec:
-
escape-for-regex-compiled
: the compiled XSpec test. -
escape-for-regex-result.xml
: the test results in XML format. -
escape-for-regex-result.html
: the human-readable HTML test report. Most of the time, this is the only file out of these three that you'll care about.
Open the HTML report at tutorial/xspec/escape-for-regex-result.html
with your favorite web browser to see the test results. The HTML report should look like this:
As you can see, one of the tests has failed.
Open the fully commented escape-for-regex.xsl
and escape-for-regex.xspec
in your favorite XML editor to follow the rest of the tutorial.
The XSLT stylesheet contains a function functx:escape-for-regex
and a matching template match="phrase"
.
The XSpec file has three top-level scenarios, which are contained in x:scenario
elements. The first two test the function, and the third tests the matching templates.
The first scenario is simple, it just calls the function functx:escape-for-regex
with the given parameter value and directly compares its result to our expected result. A function is invoked by using an x:call
element, passing it a parameter using an x:param
element. Our expectations about how the functions should behave are captured by x:expect
elements:
<x:scenario label="No escaping">
<!-- call the function with the string 'Hello' -->
<x:call function="functx:escape-for-regex">
<x:param select="'Hello'"/>
</x:call>
<!-- check the result -->
<x:expect label="Must not be escaped at all" select="'Hello'"/>
</x:scenario>
Scenarios can be nested and the second top-level scenario is an example as it contains two scenarios that test two aspects of the function functx:escape-for-regex
. The first nested scenario is an equality test, just like the first top-level scenario. The second nested scenario is more interesting as it tests the output of a function against an XPath expression given in @test
. Note that we can have as many expectations as we like within a scenario:
<x:scenario label="Test simple patterns">
<!-- call the function -->
<x:call function="functx:escape-for-regex" />
<!-- first sub-scenario -->
<x:scenario label="When encountering parentheses">
<!-- with a parameter -->
<x:call>
<x:param select="'(Hello)'"/>
</x:call>
<!-- check the result -->
<x:expect label="escape them." select="'\(Hello\)'"/>
</x:scenario>
<!-- second sub-scenario -->
<x:scenario label="When encountering a whitespace character class">
<!-- with another parameter -->
<x:call>
<x:param select="'\sHello'"/>
</x:call>
<!-- check the result -->
<x:expect label="escape the backslash" select="'\\sHello'"/>
<!-- we can have several checks on the same result -->
<x:expect label="result should have one more character than source"
test="string-length(.) = 8"/>
</x:scenario>
</x:scenario>
The third top-level scenario tests the templates in the transform. An x:context
element contains nodes we want to apply templates to. It has two expectations: the first a simple XPath test and the second demonstrates how we can directly compare the expected nodes to the actual result nodes by embedding the expected nodes as descendants of an x:expect
element:
<x:scenario label="When processing a list of phrases">
<!-- apply template rules to this element -->
<x:context>
<phrases>
<phrase>Hello!</phrase>
<phrase>Goodbye!</phrase>
<phrase>(So long!)</phrase>
</phrases>
</x:context>
<!-- check the result -->
<x:expect label="All phrase elements should remain"
test="count(phrases/phrase) = 3"/>
<x:expect label="Strings should be escaped and status attributes should be added">
<phrases>
<phrase status="same">Hello!</phrase>
<phrase status="same">Goodbye!</phrase>
<phrase status="changed">\(So long!\)</phrase>
</phrases>
</x:expect>
</x:scenario>
Although it's not shown here, both x:context
and x:call
elements have optional @href
and @select
attributes, which can be a very powerful way to define tests. @href
is used to point to an external document, and @select
is used to select certain nodes to test against.
One of the tests failed, so let's fix it. When a test fails in XSpec, the report shows both the actual result and the expected result side-by-side, with differences highlighted in pink. From this report, we can see that the failed scenario is labelled "When processing a list of phrases" and the specific expectation that failed is labelled "Strings should be escaped and status attributes should be added." The difference is that the @status
attributes contain the wrong values. Change the @status
attribute constructor to read:
<xsl:attribute name="status" select="if (. = $escaped-text) then 'same' else 'changed'" />
Save the XSLT stylesheet and re-run the XSpec test. All tests should be green:
There are many ways to integrate XSpec into your workflow. Here are a few tips:
-
Add the XSpec executable directory to your system path. For example, if XSpec is installed in
~/xspec
, add this to your~/.bashrc
:PATH=$PATH:~/xspec/bin
In Windows:
PATH %PATH%;C:\xspec\bin
-
By default, XSpec stores its result documents in the subdirectory
xspec
of the folder where the particular XSpec file that you are testing resides. You may want to change the variableTEST_DIR
to the system temporary folder:export TEST_DIR=/tmp/xspec
In Windows:
SET TEST_DIR=%TEMP%\xspec
This works well when you don't want to clutter up your project folders with XSpec results.
-
Running XSpec with Ant is far faster and more feature-rich than the shell/batch scripts.
-
XSpec is integrated in the Oxygen XML editor.