Recipe15.5.Structuring Unit Tests


Recipe 15.5. Structuring Unit Tests

Problem

You want to structure tests to simplify testing.

Solution

Notice how Recipe 15.4 embedded test data in the test stylesheets. Each test element contains a test num attribute and the correct result in the form of an ans attribute. The test driver then extracts these test elements from the stylesheet, executes the test, and compares the expected answer against the actual answer. The most important aspect of the test driver is that it produces no output when the test succeeds.

Discussion

Some of the best advice on automating testing is in Brian W. Kernighan's and Rob Pike's The Practice of Programming (Addison Wesley, 1999). The authors state that test programs should produce output only when tests fail. Why? Who wants to wade through pages of test output to look for cases where the tests fail? If you expect test code to produce no output, you will quickly notice failures when there is output. Of course, you should test your test code to make sure it actually executes before relying on this testing technique.

The method that stores the answer as an attribute in the test element works for simple tests that produce a primitive result. However, some templates produce node sets. In this case, you might need to store the correct answer as child elements in the tests. You can then use the value set operations of Recipe 9.2 to compare results. However, sometimes you can test node-set producing templates more simply. Consider the test driver for the math:lowest template. Recall that math:lowest returns a node set consisting of all instances of the lowest number in an input node set:

<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns: math="http://www.exslt.org/math" exclude-result-prefixes="math test" xmlns: test="http://www.ora.com/XSLTCookbook/test" >     <xsl:import href="math.min.xslt"/>   <xsl:template name="math:lowest">      <xsl:param name="nodes" select="/.."/>          <xsl:variable name="min">           <xsl:call-template name="math:min">                <xsl:with-param name="nodes" select="$nodes"/>           </xsl:call-template>      </xsl:variable>       <xsl:choose>           <xsl:when test="number($min) = $min">                <xsl:copy-of select="$nodes[. = $min]"/>           </xsl:when>           <xsl:otherwise/>      </xsl:choose> </xsl:template>     <!-- TEST CODE: DO NOT REMOVE! -->   <xsl:template match="xsl:stylesheet[@id='math:math.lowest'] |        xsl:include[@href='math.lowest.xslt'] " xmlns:exsl="http://exslt.org/common">     <xsl:message> TESTING math.lowest </xsl:message>     <xsl:choose>       <xsl:when test="function-available('exsl:node-set')">         <xsl:for-each select="document('')/*/test:test">           <xsl:variable name="ans">             <xsl:call-template name="math:lowest">               <xsl:with-param name="nodes" select="test:data"/>             </xsl:call-template>           </xsl:variable>            <xsl:variable name="$ans-ns" select=" exsl:node-set($ans)"/>           <xsl:if test="not($ans-ns/* != test:data[. = current( )/@ans]) and                 count($ans-ns/*) != count(test:data[. = current( )/@ans])">             <xsl:message>                 math:lowest TEST <xsl:value-of select="@num"/> FAILED                  [<xsl:copy-of select="$ans-ns"/>]                  [<xsl:copy-of select="test:data[. = current( )/@ans]"/>]           </xsl:message>           </xsl:if>         </xsl:for-each>       </xsl:when>       <xsl:otherwise>         <xsl:message>           WARNING math.lowest test code requires exsl:node-set           THIS VERSION=[<xsl:value-of select="system-property('xsl:version')"/>]           VENDOR=[<xsl:value-of select="system-property('xsl:vendor')"/>]           </xsl:message>       </xsl:otherwise>     </xsl:choose>   </xsl:template>       <test:test num="1" ans="1" 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>      <!-- more tests here ... >     </xsl:stylesheet>

The comparison relies on the behavior of != when both sides are node sets: the result is TRue if a pair of nodes, one from each node set, have different string values. You can make sure that the nodes returned by selecting the answer nodes from the test set are the same as the nodes returned by math:lowest. You can also make sure that the counts are the same.

Some forms of computation (especially mathematical approximations) produce results that are correct even when the value produced is not exactly equal to the theoretically correct answer. In this case, you can include an error tolerance in the test data and make sure the computed answer is identical to the correct answer within the stated tolerance.

See Also

Brian W. Kernighan's and Rob Pike's The Practice of Programming (Addison Wesley, 1999), although not specifically written for XSLT, contains relevant advice for testing and debugging all kinds of programs.




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