Skip to content
David Cassel edited this page Jan 13, 2014 · 13 revisions

The Roxy framework includes a unit testing component. Unit testing typically provides two main benefits:

  1. Good tests give you confidence that your code does what you think it does
  2. Tests show other developers how you expect your code will be used

Configuring and Seeing tests

To create a test app-server, make sure you have these two properties un-commented in deploy/build.properties:

test-content-db=${app-name}-content-test
test-port=8042

Change the test-port to an open port, then run "ml {env} bootstrap". Then point your browser to

http://{server}:{test-port}/test/

If you had already deployed your source code, you'll need to do so again to get the testing code in place:

ml {env} deploy modules

Filename Conventions

By convention, a test suite corresponds to a library module in your application. To get started, create a directory under src/test/suites/ named for your library module.

Inside your test suite, you can create four specially-named files:

  • setup.xqy - This module will be run before each test in your suite. Here you might insert a document into the test database that each of your tests will modify.
  • teardown.xqy - This module will run after each test in your suite. You might use this module to remove the document inserted by setup.xqy.
  • suite-setup.xqy - Run once when your suite is started. You can use this to insert some data that will not be modified over the course of the suite's tests.
  • suite-teardown.xqy - Run once when your suite is finished, to clean up after the suite's tests.

You create your test modules in the test suite directory. Typically, a module has responsibility for testing a particular function.

You can also create subdirectories in your test suite. The testing component will ignore these, so they are a good place for supporting files, like test data. Test data should be placed in a subdirectory called test-data.

As an example, consider a hypothetical library module that converts Comma Separated Values (CSV) to XML called csv-lib.xqy. Let's suppose it has a function called convert. We might test that with files like the following:

  • suites/csv-lib/suite-setup.xqy
  • suites/csv-lib/convert.xqy
  • suites/csv-lib/suite-teardown.xqy
  • suites/csv-lib/test-data/td.xqy

Why put test data into a separate module and not into suite-setup.xqy? Because this way, setup, teardown and the test(s) can all refer to the same data source, making it easier to update the tests.

Assert Functions

The testing component has a helper library that provides several assert functions:

  • assert-true($supposed-truths as xs:boolean*)
  • assert-true($supposed-truths as xs:boolean*, $msg as item()*)
  • assert-false($supposed-falsehoods as xs:boolean*)
  • assert-equal($expected as item()*, $actual as item()*)
  • assert-not-equal($expected as item()*, $actual as item()*)
  • assert-exists($item as item()*)
  • assert-all-exist($count as xs:unsignedInt, $item as item()*)
  • assert-not-exists($item as item()*)
  • assert-at-least-one-equal($expected as item()*, $actual as item()*)
  • assert-same-values($expected as item()*, $actual as item()*) - Return true if and only if the two sequences have the same values, regardless of order.
  • assert-meets-minimum-threshold($expected as xs:decimal, $actual as xs:decimal+)
  • assert-meets-maximum-threshold($expected as xs:decimal, $actual as xs:decimal+)
  • assert-throws-error($function as xdmp:function)
  • assert-throws-error($function as xdmp:function, $error-code as xs:string?)
  • assert-throws-error($function as xdmp:function, $params as item()*, $error-code as xs:string?)
  • assert-http-get-status($url as xs:string, $options as element(xdmp-http:options), $status-code)

It is good practice to use a specific assert function. So rather than:

test:assert-equal(fn:true(), $actual)`

use this instead:

test:assert-true($actual)`

Using specific asserts makes your intentions more clear to developers who read your test code.

Loading Data

The Roxy Unit Test framework simplifies loading data for your tests. Files to be loaded can be placed in a sub-directory of your test suite called test-data. The test helper provides a function which will automatically use this directory as the location of test files to be loaded.

 test:load-data-file(<name-of-file-to-be-loaded-without-path>,database id, <URI>)

example:

 test:load-test-file("test-article.xml", xdmp:database(), "/test-article.xml")

The first parameter should be set to the filename without any path elements. The database id can be determined by using the API xdmp:database(). You can also specify the name of the database as in input string to this function if need be. The URI will be the URI of the file in the database.

This should be included in the appropriate suite or test setup xquery file. In the corresponding teardown, remove the data files by referring to the URI.

let $name := "/test-article.xml" return xdmp:document-delete($name)

When loading data you

  • create the data in the test-data subdir mentioned above
  • then load the data (and any test modules) by running ml <env> deploy modules. This copies all data to the Server
  • at runtime the test data is loaded into your test-content-db from the modules database or filesystem if you are running out of the filesystem.

Unit Testing Patterns