Recipe15.4.Including Embedded Unit Test Data in Utility Stylesheets


Recipe 15.4. Including Embedded Unit Test Data in Utility Stylesheets

Problem

You want to package tests with your utility stylesheets so they can be verified at any time.

Solution

The following stylesheet is meant to be included as a utility. However, this example provides the capability of testing the stylesheet by executing it as its own input document:

<!-- math.max.xslt -->     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:math="http://www.exslt.org/math" exclude-result-prefixes="math" xmlns:test="http://www.ora.com/XSLTCookbook/test" >     <xsl:template name="math:max">      <xsl:param name="nodes" select="/.."/>      <xsl:param name="max"/>   <xsl:variable name="count" select="count($nodes)"/>   <xsl:variable name="aNode" select="$nodes[ceiling($count div 2)]"/>   <xsl:choose>     <xsl:when test="not($count)">       <xsl:value-of select="number($max)"/>     </xsl:when>     <xsl:when test="number($aNode) != number($aNode)">       <xsl:value-of select="number($aNode)"/>     </xsl:when>     <xsl:otherwise>       <xsl:call-template name="math:max">         <xsl:with-param name="nodes" select="$nodes[not(. &lt;= number($aNode))]"/>         <xsl:with-param name="max">           <xsl:choose>             <xsl:when test="not($max) or $aNode > $max">               <xsl:value-of select="$aNode"/>             </xsl:when>             <xsl:otherwise>               <xsl:value-of select="$max"/>             </xsl:otherwise>           </xsl:choose>         </xsl:with-param>       </xsl:call-template>     </xsl:otherwise>   </xsl:choose> </xsl:template>     <!-- TEST CODE: DO NOT REMOVE! --> <xsl:template match="/xsl:stylesheet[@id='math:math.max'] | xsl:include[@href='math. max.xslt'] " priority="-1000"> <xsl:message> TESTING math.max </xsl:message>     <xsl:for-each select="document('')/*/test:test">      <xsl:variable name="ans">           <xsl:call-template name="math:max">                <xsl:with-param name="nodes" select="test:data"/>           </xsl:call-template>      </xsl:variable>      <xsl:if test="$ans != @ans">           <xsl:message>                math:max TEST <xsl:value-of select="@num"/> FAILED [<xsl:value-of  select="$ans"/>]           </xsl:message>      </xsl:if> </xsl:for-each>     <!-- Test with Infinity --> <xsl:variable name="ans1">      <xsl:call-template name="math:max">           <xsl:with-param name="nodes" select="document('')/*/test:test[@num=1]/test: data"/>           <xsl:with-param name="max" select="1 div 0"/>      </xsl:call-template> </xsl:variable> <xsl:if test="$ans1 != Infinity">      <xsl:message>           math:max Infinity Test FAILED [<xsl:value-of select="$ans1"/>]      </xsl:message> </xsl:if>     <!-- Test with -Infinity --> <xsl:variable name="ans2">      <xsl:call-template name="math:max">           <xsl:with-param name="nodes" select="document('')/*/test:test[@num=1]/test: data"/>           <xsl:with-param name="max" select="-1 div 0"/>      </xsl:call-template> </xsl:variable> <xsl:if test="$ans2 != document('')/*/test:test[@num=1]/@ans">      <xsl:message>           math:max -Infinity Test FAILED [<xsl:value-of select="$ans2"/>]      </xsl:message> </xsl:if>     </xsl:template>     <test:test num="1" ans="9" xmlns="http://www.ora.com/XSLTCookbook/test">      <data>9</data>      <data>8</data>      <data>7</data>      <data>6</data>      <data>5</data>      <data>4</data>      <data>3</data>      <data>2</data>      <data>1</data> </test:test>     <test:test num="2" ans="1" xmlns="http://www.ora.com/XSLTCookbook/test">      <data>1</data> </test:test>     <test:test num="3" ans="1" xmlns="http://www.ora.com/XSLTCookbook/test">      <data>-1</data>      <data>1</data> </test:test>     <test:test num="4" ans="0" xmlns="http://www.ora.com/XSLTCookbook/test">      <data>0</data>      <data>0</data> </test:test>     <test:test num="5" ans="NaN" xmlns="http://www.ora.com/XSLTCookbook/test">      <data>foo</data>      <data>1</data> </test:test>     <test:test num="6" ans="NaN" xmlns="http://www.ora.com/XSLTCookbook/test">      <data>1</data>      <data>foo</data> </test:test>     <test:test num="7" ans="NaN" xmlns="http://www.ora.com/XSLTCookbook/test"> </test:test>     </xsl:stylesheet>

Discussion

The xsl:stylesheet element has an optional attribute called id. This attribute idenfities stylesheets that are embedded in larger documents. However, here the ID is used for testing purposes. You want to package test code with the stylesheet but make reasonably certain that this test code does not interfere with the normal usage of the stylesheet. Do this by creating a template that will match only when the stylesheet processes itself:

<xsl:template match="/xsl:stylesheet[@id='math:math.max'] |      xsl:include[@href='math.max.xslt']">

This explains the /xsl:stylesheet[@id='math:math.max'], but what about the xsl:include[@href='math.max.xslt'] part? To see the value of this, here is a stylesheet that packages all your math utilities into a single file for easy inclusion. You would like an easy way to test the entire package too:

<!-- math.xslt -->     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"      xmlns:math="http://exslt.org/math"       extension-element-prefixes="math" >     <xsl:include href="math.abs.xslt"/> <xsl:include href="math.constant.xslt"/> <xsl:include href="math.exp.xslt"/> <xsl:include href="math.highest.xslt"/> <xsl:include href="math.log.xslt"/> <xsl:include href="math.lowest.xslt"/> <xsl:include href="math.max.xslt"/> <xsl:include href="math.min.xslt"/> <xsl:include href="math.power.xslt"/> <xsl:include href="math.sqrt.xslt"/>     <!--TEST CODE --> <xsl:template match="xsl:stylesheet[@id='math:math'] | xsl:include[@href='math. xslt']">     <xsl:message> TESTING math </xsl:message>          <xsl:for-each select="document('')/*/xsl:include">           <xsl:apply-templates select="."/>      </xsl:for-each> </xsl:template>     <xsl:template match="xsl:include" priority="-10">      <xsl:message>      WARNING: <xsl:value-of select="@href"/> has no test code.      </xsl:message> </xsl:template>     </xsl:stylesheet>

Here you see that the test code for a package simply loops over all its xsl:include elements and applies templates to them. This step causes each included stylesheet tests to be exercised due to the aforementioned xsl:include[@href='filename'] part of the match.

Notice the template <xsl:template match="xsl:include" priority="-10">. This template causes emission of a warning if an included file does not contain test code. This concept is important for quality control, since forgetting to create tests is easy.

If you object to packaging the tests with the actual code, you can achieve the same effect by creating separate test files for each utility. In this case, there is no need to use the id attribute of the stylesheet; simply match against the root:

<!-- math.max.test.xslt-->     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:math="http://www.exslt.org/math" exclude-result-prefixes="math" xmlns:test="http://www.ora.com/XSLTCookbook/test">     <xsl:include href="../math/math.max.xslt"/>     <!-- TEST CODE: DO NOT REMOVE! --> <xsl:template match="/ | xsl:include[@href='math.max.test.xslt']"> <xsl:message> TESTING math.max </xsl:message>     <xsl:for-each select="document('')/*/test:test">      <xsl:variable name="ans">           <xsl:call-template name="math:max">                <xsl:with-param name="nodes" select="test:data"/>           </xsl:call-template>      </xsl:variable>      <xsl:if test="$ans != @ans">           <xsl:message>                math:max TEST <xsl:value-of select="@num"/> FAILED [<xsl:value-of  select="$ans"/>]           </xsl:message>      </xsl:if> </xsl:for-each>     <!-- ... Same as math.max.xslt above ... -->     </xsl:stylesheet>

You would then create separate test packages:

<!-- math.test.xslt -->     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"      xmlns:math="http://exslt.org/math"       extension-element-prefixes="math">     <xsl:include href="math.max.test.xslt"/> <xsl:include href="math.min.test.xslt"/>     <!-- ... Same as math.xslt, above ... -->     </xsl:stylesheet>

If you separate your tests in this way, be sure to ship the test code with the actual implementations. Doing so allows your clients to verify tests for themselves. The test code also doubles as an example of how to use the templates.




XSLT Cookbook
XSLT Cookbook: Solutions and Examples for XML and XSLT Developers, 2nd Edition
ISBN: 0596009747
EAN: 2147483647
Year: 2003
Pages: 208
Authors: Sal Mangano

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net