"Test Runner" is a unit testing framework that fully supports testing qooxdoo classes. It is similar to but does not require JSUnit or any other JavaScript unit testing framework. If you look at the component section of a qooxdoo distribution under component/testrunner/, you will find the Test Runner sources, together with a mockup test class. In the framework/ section you can create a Test Runner instance with all test classes from the qooxdoo framework by running:
./generate.py test
Test Runner provides a convenient interface to test classes that have been written to that end. You can run single tests, or run a whole suite of them at once.
Note
See the Test Runner in action in the online demo.
The Test Runner framework can also be deployed for your own application. It provides a GUI, a layer of infrastructure and a certain interface for arbitrary test classes. So now you can write your own test classes and take advantage of the Test Runner environment.
This section assumes that your qooxdoo application bears on the structure of the qooxdoo skeleton application. Then this is what you have to do:
Test classes can optionally define a setUp method. This is used to initialize common objects needed by some or all of the tests in the class. Since setUp is executed before each test, it helps to ensure that each test function runs in a "clean" environment. Similarly, a method named tearDown will be executed after each test, e.g. to dispose any objects created by setUp or the test itself.
For cases where the generic class-wide tearDown isn't enough, methods using the naming convention tearDown<TestFunctionName> can be defined. A method named e.g. tearDownTestFoo would be called after testFoo and the generic tearDown of the class were executed.
Starting with qooxdoo 0.8.2, the unit testing framework supports asynchronous tests. This enables testing for methods that aren't called directly, such as event handlers:
Here's an example: In our test, we want to send an AJAX request to the local web server, then assert if the response is what we expect it to be.
testAjaxRequest : function()
{
var request = new qx.io.remote.Request("/myWebApp/index.html");
request.addListener("completed", function (e) {
this.resume(function() {
this.assertEquals(200, e.getStatusCode());
}, this);
}, this);
request.send();
this.wait(10000);
}
Requirements are conditions that must be met before a test can be run. For example, a test might rely on the application having been loaded over HTTPS and would give false results otherwise. Requirements are defined for individual tests; if one or more aren't satisfied, the test code won't be executed and the test will be marked as "skipped" in the Test Runner's results list.
The make use of the requirements feature, test classes must include the MRequirements mixin. The mixin defines a method require that takes an array of strings: The requirement IDs. This method is either called from the setUp method or from a test function before the actual logic of the test, e.g.:
testSslRequest : function()
{
this.require(["ssl"]);
// test code goes here
}
require then searches the current test instance for a method that verifies the listed requirements: The naming convention is "has" + the requirement ID with the first letter capitalized, e.g. hasSsl. This method is the called with the requirement ID as the only parameter. If it returns true, the test code will be executed. Otherwise a RequirementError is thrown. The Test Runner will catch these and mark the test as "skipped" in the results list. Any test code after the require call will not be executed.
In addition to the verification methods in MRequirements, test developers can define their own right in the test class.
Run generate.py test from the top-level directory of your application. This will generate the appropriate test application for you, which will be available in the subfolder test as test/index.html. Open this file in your browser and run your tests.
Equally, you can invoke generate.py test-source. This will generate the test application, but allows you to use the source version of your application to run the tests on. In doing so the test application links directly into the source tree of your application. This allows for test-driven development where you simultaneously develop your source classes, the test classes and run the tests. All you need to do is to change the URL of the "test backend application" (the textfield in the upper middle of the Test Runner frame) from tests.html (which is the default) to tests-source.html. (Caveat: If generate.py test-source is the first thing you do, you might get an error when Test Runner starts, since the default tests.html has not been built; just change the URL and continue). For example, the resulting URL will look something like this:
html/tests-source.html?testclass=<your_app_name>
After that, you just reload the backend application by hitting the reload button to the right to see and test your changes in the Test Runner.
If you're working on an application based on qx.application.Native or qx.application.Inline (e.g. by starting with an Inline skeleton), you can run generate.py test-native or generate.py test-inline to create a test application of the same type as your actual application. The Test Runner's index file will be called index-native.html or index-inline.html, respectively.
The Testrunner architecture is split between the logic that executes tests and the view that displays the results and allows the user to select which tests to run. Views are selected by overriding the TESTRUNNER_VIEW configuration macro, specifying the desired view class. For example, to build the Test Runner using the HTML view, use the following shell command:
./generate.py test -m TESTRUNNER_VIEW:testrunner.view.Console
Several views are included with the Test Runner:
This is the default view used for the GUI, Native and Inline skeletons' test and test-source jobs. It is the most fully-featured and convenient to use, making heavy use of data binding to list available tests in a Virtual Tree and to visualize the results. The downside is that can it feel sluggish in environments with poor JavaScript performance.
As the name indicates, this view uses plain (D)HTML instead of qooxdoo's UI layer. It is intended for usage scenarios where speed is more important than good looks.
Even more bare-bones than the HTML view, the Console view features no visual elements other than the Iframe containing the test application. Tests are started using the browser's JavaScript console. This is mostly intended as a base for specialized views.
This view visualizes the results of performance tests using the qx.test.performance.MMeasure mixin. Take a look at the tests in the qx.test.performance namespace and the test-performance job in framework/config.json to see how you can implement performance tests measuring JavaScript execution and HTML rendering time for your application.
The Reporter is a specialized view used for automated unit test runs. Based on the Console view, it features (almost) no GUI. The test suite is automatically started as soon as it's ready. A method that returns a map of failed tests is its only means of interaction:
qx.core.Init.getApplication().runner.view.getFailedResults()