Difference between revisions of "Unit Module"
Line 5: | Line 5: | ||
The more complex a software application grows, the more error-prone it gets. This is why testing frameworks have been developed, which provide a standardized, automatized way for testing software. The [http://en.wikipedia.org/wiki/XUnit XUnit] frameworks (such as SUnit or JUnit) allow testing of atomic unit of a program, such as single functions and algorithms. | The more complex a software application grows, the more error-prone it gets. This is why testing frameworks have been developed, which provide a standardized, automatized way for testing software. The [http://en.wikipedia.org/wiki/XUnit XUnit] frameworks (such as SUnit or JUnit) allow testing of atomic unit of a program, such as single functions and algorithms. | ||
− | + | This module borrows heavily from the existing frameworks: it introduces various new annotations for testing XQuery functions. Unit functions are provided to assert the validity of arbitrary conditions expressed in XQuery and to raise errors whenever a condition is not satisfied. Some additional functions exist to run all unit tests of the current module or a set of specified library modules. | |
Please note that this module is still in beta stage, and its functionality is still subject to change. Your feedback is welcome. | Please note that this module is still in beta stage, and its functionality is still subject to change. Your feedback is welcome. | ||
Line 11: | Line 11: | ||
=Conventions= | =Conventions= | ||
− | Both functions and errors in this module are assigned to the {{Code|http://basex.org/modules/ | + | Both functions and errors in this module are assigned to the {{Code|http://basex.org/modules/unit}} namespace, which is statically bound to the {{Code|unit}} prefix.<br/> |
=Annotations= | =Annotations= | ||
− | ==% | + | ==%unit:test== |
{| width='100%' | {| width='100%' | ||
|- | |- | ||
| width='90' | '''Syntax''' | | width='90' | '''Syntax''' | ||
− | |{{Code|% | + | |{{Code|%unit:test}}<br/>{{Code|%unit:test("expected", <ERROR>)}} |
|- | |- | ||
| '''Summary''' | | '''Summary''' | ||
− | |With this annotation, a function can be marked as | + | |With this annotation, a function can be marked as unit test. It will be evaluated whenever a test report is created for the module in which this function is located.<br/>If an optional error code is specified and if the function expression does not raise that error, the test will fail. |
|} | |} | ||
− | ==% | + | ==%unit:before== |
{| width='100%' | {| width='100%' | ||
|- | |- | ||
| width='90' | '''Syntax''' | | width='90' | '''Syntax''' | ||
− | |{{Code|% | + | |{{Code|%unit:before}} |
|- | |- | ||
| '''Summary''' | | '''Summary''' | ||
− | |A function decorated with this annotation will be evaluated '''before each''' | + | |A function decorated with this annotation will be evaluated '''before each''' unit test. |
|} | |} | ||
− | ==% | + | ==%unit:after== |
{| width='100%' | {| width='100%' | ||
|- | |- | ||
| width='90' | '''Syntax''' | | width='90' | '''Syntax''' | ||
− | |{{Code|% | + | |{{Code|%unit:after}} |
|- | |- | ||
| '''Summary''' | | '''Summary''' | ||
− | |A function decorated with this annotation will be evaluated '''after each''' | + | |A function decorated with this annotation will be evaluated '''after each''' unit test. |
|} | |} | ||
− | ==% | + | ==%unit:before-module== |
{| width='100%' | {| width='100%' | ||
|- | |- | ||
| width='90' | '''Syntax''' | | width='90' | '''Syntax''' | ||
− | |{{Code|% | + | |{{Code|%unit:before-module}} |
|- | |- | ||
| '''Summary''' | | '''Summary''' | ||
− | |If a function is decorated with this annotation, it will be evaluated '''before all''' | + | |If a function is decorated with this annotation, it will be evaluated '''before all''' unit tests in the current module. |
|} | |} | ||
− | ==% | + | ==%unit:after-module== |
{| width='100%' | {| width='100%' | ||
|- | |- | ||
| width='90' | '''Syntax''' | | width='90' | '''Syntax''' | ||
− | |{{Code|% | + | |{{Code|%unit:after-module}} |
|- | |- | ||
| '''Summary''' | | '''Summary''' | ||
− | |If a function is decorated with this annotation, it will be evaluated '''after all''' | + | |If a function is decorated with this annotation, it will be evaluated '''after all''' unit tests in the current module. |
|} | |} | ||
− | ==% | + | ==%unit:ignore== |
{| width='100%' | {| width='100%' | ||
|- | |- | ||
| width='90' | '''Syntax''' | | width='90' | '''Syntax''' | ||
− | |{{Code|% | + | |{{Code|%unit:ignore}}<br/>{{Code|%unit:ignore("message")}} |
|- | |- | ||
| '''Summary''' | | '''Summary''' | ||
Line 77: | Line 77: | ||
=Functions= | =Functions= | ||
− | == | + | ==unit:assert== |
{| width='100%' | {| width='100%' | ||
|- | |- | ||
| width='90' | '''Signatures''' | | width='90' | '''Signatures''' | ||
− | |{{Func| | + | |{{Func|unit:assert|$test as item()*|empty-sequence()}}<br />{{Func|unit:assert|$test as item()*, $message as xs:string|empty-sequence()}}<br /> |
|- | |- | ||
| '''Summary''' | | '''Summary''' | ||
Line 87: | Line 87: | ||
|- | |- | ||
| '''Errors''' | | '''Errors''' | ||
− | |{{Error| | + | |{{Error|UNIT0001|#Errors}} the assertion failed, or an error was raised. |
|} | |} | ||
− | == | + | ==unit:fail== |
{| width='100%' | {| width='100%' | ||
|- | |- | ||
| width='90' | '''Signatures''' | | width='90' | '''Signatures''' | ||
− | |{{Func| | + | |{{Func|unit:fail|$message as xs:string|empty-sequence()}}<br /> |
|- | |- | ||
| '''Summary''' | | '''Summary''' | ||
− | |Raises | + | |Raises a unit error with the specified message. |
|- | |- | ||
| '''Errors''' | | '''Errors''' | ||
− | |{{Error| | + | |{{Error|UNIT0001|#Errors}} default error raised by this function. |
|} | |} | ||
− | == | + | ==unit:test== |
{| width='100%' | {| width='100%' | ||
|- | |- | ||
| width='90' | '''Signatures''' | | width='90' | '''Signatures''' | ||
− | |{{Func| | + | |{{Func|unit:test||element(testsuite)*}}<br /> |
|- | |- | ||
| '''Summary''' | | '''Summary''' | ||
− | |Runs all functions in the current module that are annotated with {{Code| | + | |Runs all functions in the current module that are annotated with {{Code|unit}} annotations.<br />A test report is generated and returned, which resembles the format returned by other xUnit testing frameworks, such as the Maven Surefire Plugin. |
|- | |- | ||
| '''Errors''' | | '''Errors''' | ||
− | |{{Error| | + | |{{Error|UNIT0002|#Errors}} a test function must have no arguments.<br/>{{Error|UNIT0003|#Errors}} a test function must not be updating.<br/>{{Error|UNIT0004|#Errors}} an annotation was declared twice.<br/>{{Error|UNIT0005|#Errors}} an annotation has invalid arguments. |
|} | |} | ||
− | == | + | ==unit:test-libraries== |
{| width='100%' | {| width='100%' | ||
|- | |- | ||
| width='90' | '''Signatures''' | | width='90' | '''Signatures''' | ||
− | |{{Func| | + | |{{Func|unit:test-libraries|$uris as xs:string*|element(testsuites)}}<br /> |
|- | |- | ||
| '''Summary''' | | '''Summary''' | ||
− | |Runs all functions in the specified modules that are annotated with {{Code| | + | |Runs all functions in the specified modules that are annotated with {{Code|unit}} annotations.<br />A test report is generated and returned, which resembles the format returned by other xUnit testing frameworks, such as the Maven Surefire Plugin. |
|- | |- | ||
| '''Errors''' | | '''Errors''' | ||
− | |{{Error| | + | |{{Error|UNIT0002|#Errors}} a test function must have no arguments.<br/>{{Error|UNIT0003|#Errors}} a test function must not be updating.<br/>{{Error|UNIT0004|#Errors}} an annotation was declared twice.<br/>{{Error|UNIT0005|#Errors}} an annotation has invalid arguments. |
|} | |} | ||
=Example= | =Example= | ||
− | The following XQuery main module creates a test report. It contains all available | + | The following XQuery main module creates a test report. It contains all available unit annotations: |
'''Query:''' | '''Query:''' | ||
Line 138: | Line 138: | ||
(:~ Initializing function, which is called once before all tests. :) | (:~ Initializing function, which is called once before all tests. :) | ||
declare | declare | ||
− | % | + | %unit:before-module |
function local:before-all-tests() { () | function local:before-all-tests() { () | ||
}; | }; | ||
Line 144: | Line 144: | ||
(:~ Initializing function, which is called once after all tests. :) | (:~ Initializing function, which is called once after all tests. :) | ||
declare | declare | ||
− | % | + | %unit:after-module |
function local:after-all-tests() { () | function local:after-all-tests() { () | ||
}; | }; | ||
Line 150: | Line 150: | ||
(:~ Initializing function, which is called before each test. :) | (:~ Initializing function, which is called before each test. :) | ||
declare | declare | ||
− | % | + | %unit:before |
function local:before() { () | function local:before() { () | ||
}; | }; | ||
Line 156: | Line 156: | ||
(:~ Initializing function, which is called after each test. :) | (:~ Initializing function, which is called after each test. :) | ||
declare | declare | ||
− | % | + | %unit:after |
function local:after() { () | function local:after() { () | ||
}; | }; | ||
Line 162: | Line 162: | ||
(:~ Function demonstrating a successful test. :) | (:~ Function demonstrating a successful test. :) | ||
declare | declare | ||
− | % | + | %unit:test |
function local:success-function() { | function local:success-function() { | ||
− | + | unit:assert(1 + 2 = 3) | |
}; | }; | ||
(:~ Function demonstrating a failure. :) | (:~ Function demonstrating a failure. :) | ||
declare | declare | ||
− | % | + | %unit:test |
function local:failure-function() { | function local:failure-function() { | ||
− | + | unit:assert(4 + 5 = 6) | |
}; | }; | ||
(:~ Function demonstrating an expected error. :) | (:~ Function demonstrating an expected error. :) | ||
declare | declare | ||
− | % | + | %unit:test("expected", "FORG0001") |
function local:expected-success() { | function local:expected-success() { | ||
() | () | ||
Line 183: | Line 183: | ||
(:~ Function demonstrating an expected error. :) | (:~ Function demonstrating an expected error. :) | ||
declare | declare | ||
− | % | + | %unit:test("expected", "FORG0001") |
function local:expected-error() { | function local:expected-error() { | ||
1 + <a/> | 1 + <a/> | ||
Line 190: | Line 190: | ||
(:~ Function demonstrating an error. :) | (:~ Function demonstrating an error. :) | ||
declare | declare | ||
− | % | + | %unit:test |
function local:error-function() { | function local:error-function() { | ||
1 + <a/> | 1 + <a/> | ||
Line 197: | Line 197: | ||
(:~ Skipping a test. :) | (:~ Skipping a test. :) | ||
declare | declare | ||
− | % | + | %unit:test %unit:ignore("Skipped!") |
function local:skipped-function() { | function local:skipped-function() { | ||
() | () | ||
Line 203: | Line 203: | ||
(: run all tests :) | (: run all tests :) | ||
− | + | unit:test() | |
</pre> | </pre> | ||
Line 233: | Line 233: | ||
! width="95%"|Description | ! width="95%"|Description | ||
|- | |- | ||
− | |{{Code| | + | |{{Code|UNIT0001}} |
|An assertion failed, or an error was raised. | |An assertion failed, or an error was raised. | ||
|- | |- | ||
− | |{{Code| | + | |{{Code|UNIT0002}} |
|A test function must have no arguments. | |A test function must have no arguments. | ||
|- | |- | ||
− | |{{Code| | + | |{{Code|UNIT0003}} |
|A test function must not be updating. | |A test function must not be updating. | ||
|- | |- | ||
− | |{{Code| | + | |{{Code|UNIT0004}} |
|An annotation was declared twice. | |An annotation was declared twice. | ||
|- | |- | ||
− | |{{Code| | + | |{{Code|UNIT0005}} |
|An annotation has invalid arguments. | |An annotation has invalid arguments. | ||
|} | |} |
Revision as of 17:55, 29 May 2013
This XQuery Module contains annotations and functions for performing Unit tests with XQuery.
Contents
Introduction
The more complex a software application grows, the more error-prone it gets. This is why testing frameworks have been developed, which provide a standardized, automatized way for testing software. The XUnit frameworks (such as SUnit or JUnit) allow testing of atomic unit of a program, such as single functions and algorithms.
This module borrows heavily from the existing frameworks: it introduces various new annotations for testing XQuery functions. Unit functions are provided to assert the validity of arbitrary conditions expressed in XQuery and to raise errors whenever a condition is not satisfied. Some additional functions exist to run all unit tests of the current module or a set of specified library modules.
Please note that this module is still in beta stage, and its functionality is still subject to change. Your feedback is welcome.
Conventions
Both functions and errors in this module are assigned to the http://basex.org/modules/unit
namespace, which is statically bound to the unit
prefix.
Annotations
%unit:test
Syntax | %unit:test %unit:test("expected", <ERROR>)
|
Summary | With this annotation, a function can be marked as unit test. It will be evaluated whenever a test report is created for the module in which this function is located. If an optional error code is specified and if the function expression does not raise that error, the test will fail. |
%unit:before
Syntax | %unit:before
|
Summary | A function decorated with this annotation will be evaluated before each unit test. |
%unit:after
Syntax | %unit:after
|
Summary | A function decorated with this annotation will be evaluated after each unit test. |
%unit:before-module
Syntax | %unit:before-module
|
Summary | If a function is decorated with this annotation, it will be evaluated before all unit tests in the current module. |
%unit:after-module
Syntax | %unit:after-module
|
Summary | If a function is decorated with this annotation, it will be evaluated after all unit tests in the current module. |
%unit:ignore
Syntax | %unit:ignore %unit:ignore("message")
|
Summary | If a function is decorated with this annotation, it will temporarily be ignored by the test suite runner. |
Functions
unit:assert
Signatures | unit:assert($test as item()*) as empty-sequence() unit:assert($test as item()*, $message as xs:string) as empty-sequence() |
Summary | Asserts that the effective boolean value of the specified $test is true and returns an empty sequence. Otherwise, raises an error.If the optional error $message can be specified as second argument.
|
Errors | UNIT0001 : the assertion failed, or an error was raised.
|
unit:fail
Signatures | unit:fail($message as xs:string) as empty-sequence() |
Summary | Raises a unit error with the specified message. |
Errors | UNIT0001 : default error raised by this function.
|
unit:test
Signatures | unit:test() as element(testsuite)* |
Summary | Runs all functions in the current module that are annotated with unit annotations.A test report is generated and returned, which resembles the format returned by other xUnit testing frameworks, such as the Maven Surefire Plugin. |
Errors | UNIT0002 : a test function must have no arguments.UNIT0003 : a test function must not be updating.UNIT0004 : an annotation was declared twice.UNIT0005 : an annotation has invalid arguments.
|
unit:test-libraries
Signatures | unit:test-libraries($uris as xs:string*) as element(testsuites) |
Summary | Runs all functions in the specified modules that are annotated with unit annotations.A test report is generated and returned, which resembles the format returned by other xUnit testing frameworks, such as the Maven Surefire Plugin. |
Errors | UNIT0002 : a test function must have no arguments.UNIT0003 : a test function must not be updating.UNIT0004 : an annotation was declared twice.UNIT0005 : an annotation has invalid arguments.
|
Example
The following XQuery main module creates a test report. It contains all available unit annotations:
Query:
(:~ Initializing function, which is called once before all tests. :) declare %unit:before-module function local:before-all-tests() { () }; (:~ Initializing function, which is called once after all tests. :) declare %unit:after-module function local:after-all-tests() { () }; (:~ Initializing function, which is called before each test. :) declare %unit:before function local:before() { () }; (:~ Initializing function, which is called after each test. :) declare %unit:after function local:after() { () }; (:~ Function demonstrating a successful test. :) declare %unit:test function local:success-function() { unit:assert(1 + 2 = 3) }; (:~ Function demonstrating a failure. :) declare %unit:test function local:failure-function() { unit:assert(4 + 5 = 6) }; (:~ Function demonstrating an expected error. :) declare %unit:test("expected", "FORG0001") function local:expected-success() { () }; (:~ Function demonstrating an expected error. :) declare %unit:test("expected", "FORG0001") function local:expected-error() { 1 + <a/> }; (:~ Function demonstrating an error. :) declare %unit:test function local:error-function() { 1 + <a/> }; (:~ Skipping a test. :) declare %unit:test %unit:ignore("Skipped!") function local:skipped-function() { () }; (: run all tests :) unit:test()
Result:
<testsuite name="/path/to/tests.xq" time="PT0S" tests="6" failures="2" errors="1" skipped="1"> <testcase name="success-function" time="PT0S"/> <testcase name="failure-function" time="PT0S"> <failure message="Assertion failed." type="UNIT0001"/> </testcase> <testcase name="expected-success" time="PT0S"> <failure message="Error expected." type="FORG0001"/> </testcase> <testcase name="expected-error" time="PT0S"/> <testcase name="error-function" time="PT0S"> <error message="Invalid xs:double cast: ." type="FORG0001"/> </testcase> <testcase name="skipped-function" time="PT0S"> <skipped message="Skipped!"/> </testcase> </testsuite>
Errors
Code | Description |
---|---|
UNIT0001
|
An assertion failed, or an error was raised. |
UNIT0002
|
A test function must have no arguments. |
UNIT0003
|
A test function must not be updating. |
UNIT0004
|
An annotation was declared twice. |
UNIT0005
|
An annotation has invalid arguments. |
Changelog
This module was introduced with Version 7.7.