Skip to content

Test Module Service

StephenCote edited this page Sep 30, 2013 · 1 revision

Introduction

The Hemi JavaScript Framework includes a set of APIs, Templates, and Fragments for creating and executing unit tests (Ra Ra Test Driven Development). These features can be used to write tests for any Web page or JavaScript toolkit.

Related Reading

Approach

Test Modules are modules with additional instrumentation:

  • All global functions defined in the external script that begin with Test are treated as unit test, and all discovered Tests are stored in the TestMembers property.
  • A Task is created with named dependencies on the identified Tests, and thus create a Suite.
  • The dynamic Continue* (paired with the HandleContinue* virtual method) and [End*](http://www.whitefrost.com/Hemi/api/hemi.app.module.test.html#TestModule methods are injected for anonymous asynchronous handling.
  • The Logger utility is instrumented.
  • The ResetSuite, RunTest and RunTests methods are injected to orchestrate test tasking, run a named test, and run all discovered tests.
  • TestResults are available from the Test Module via the Tests Accessor, particularly getTests and getTestByName.
  • Test and TestSuite callbacks can be specified via the NewTest constructor.

For example, given a script file /SomeDir/mytest.js, the following would represent one synchronous test for an HTML node (the connection between the two will follow).

Synchronous Example

<!-- Some HTML -->
<p id = "oPara">Some Content</p>

/// /SomeDir/mytest.js
///
function TestContent(){
   this.Assert(Hemi.xml.getInnerText(Container).match(/Some Content/), "Content not found");
}

Running the Example

To run this example, the test must be loaded for the HTML node:

/// Note: The name is the file name without the .js extension
var oTest = Hemi.app.module.test.NewTest("mytest", document.getElementById("oPara"), 0, 0, "/SomeDir/");
/// Run all tests
oTest.RunTests();

/// For synchronous testing only:
/// Get a named test result:
///
var oTestResult = oTest.getTestByName("TestContent");

/// Get a formatted report of all test results
///
var sReport = oTest.getReport();

Asynchronous Example

Asynchronous tests are supported by returning false from a given Test, completed by using the dynamic Continue and virtual HandleContinue methods, and/or the dynamic End method.

The following example demonstrates an asynchronous test that asynchronously loads some xml, changes the Container content, and then makes an assertion about the result.

<!-- Some HTML -->
<p id = "oPara">Some Content</p>

/// /SomeDir/mytest.js
///
function TestAsyncContent(){
   Hemi.xml.getXml("/SomeXml.xml",LoadXml,1);
   return false;
}
function LoadXml(sName, vData){
   /// Copy XML contents into HTML node
   if(vData.xdom) Hemi.xml.setInnerXHTML(Container, vData.xdom);
   ContinueTestAsyncContent();
}
function HandleContinueTestAsyncContent(){
   this.Assert(Hemi.xml.getInnerText(Container).match(/Some Content From XML/), "Content not found");
   return true;
}

Running the Example

To run this example, the test must be loaded for the HTML node, and a callback defined to receive the results once the test status changes.

/// Invoked when the Test status changes
function HandleTestStatus(oTest, oTestModule, iState){

}
/// Invoked when the test suite has completed running
function HandleTestSuite(oTestModule){

}

/// Note: The name is the file name without the .js extension
var oTest = Hemi.app.module.test.NewTest("mytest", document.getElementById("oPara"), HandleTestStatus,HandleTestSuite, "/SomeDir/");
oTest.RunTests();

Test Components and Templates

The Hemi JavaScript Framework includes features for working with tests and Test Modules, and to streamline the connection between HTML nodes and tests without relying on global identifiers and custom scripting.

Testable Component

The Application Component component.testable.xml loads a set of tests defined for a particular HTML node, and renders visual indicators for the test status.

The component is loaded via the Application Space Service, and instrumented by the XHTMLComponent class. Both of these activities are handled automatically and behind the scenes - no custom scripting is required.

The testable component supports the following attributes:

  • tests : An array of test module names.
  • test-path: The base path where the tests are located, if not in the Hemi/Tests/ directory.
  • auto-test: Bit indicating to automatically run the tests.
  • test-target: Optional HTML id to use as the Container instead of the node on which the tests are defined.

For example, given some HTML:

<p>Some Content</p>

The testable component and test configuration can be defined as a set of attributes, which in addition to instrumenting the tests also render a UI for viewing results:

Some Content

TestSuite Template

The TestSuite.xml template and TestSuite.xml fragment are provided to interact with and customize defined tests.

The test suite is straightforward to load by directly referencing the Template, and then setting a custom list of tests on the suite.

<input type = "button" value = "Test Suite" onclick = "Hemi.app.createWindow('Test Suite','Templates/TestSuite.xml', 'TestSuite');" />

var g_tests = "mytest";
var g_testdir = "/SomeDir/";
/// Listen for when the template loads and then set the test properties
///
Hemi.message.service.subscribe("ontemplateload", function (s, v) {
    if (v.getContainerComponentId() != "TestSuite") return;
    v.setTests(g_tests.split(","), g_testdir);
});

Defining Tests in Encoded JSON CSS

The Hemi JavaScript Framework includes a utility to decode JSON from a CSS class name. This allows test configuration to be encoded, such as:

<p class = "{#HF_WebUnit{testPath:'/SomeDir/',tests:'mytest'}}"">Example Content</p>

And then using Hemi, or any framework that indexes by CSS class such as JQuery, can be used to extract the nodes with this class, so that:

var oNode = ...;
var sClass = "{#HF_WebUnit{testPath:'/SomeDir/',tests:'mytest'}}";
var oConfig = Hemi.css.decodeJSON(sClass);
var oTest = var oTest = Hemi.app.module.test.NewTest(oConfig.WebUnit.tests[0], oNode, 0, 0,oConfig.WebUnit.testPath);
oTest.RunTests();

Refer to the Get Started with Hemi and TDD article for a more detailed example using the Application Space Service.

Handling Test Results

When a test is started per Test Module instance, a TestResult is created. The TestResult object is available as a parameter to the Test* and HandleContinueTest* test methods, and the test handler specified in the constructor. Test results can be retrieved from a Test Module instance via the getTests and getTestByName methods.

The following TestResult demonstrates how a failing and incomplete test result may appear.

  • name: TestCrossUsePacketTransaction
  • start_time: [Date/Time]
  • stop_time: 0
  • messages: ["Packet was not handled"]
  • result: 0
  • error: 1
  • status: 3

Report

The getReport method is a convenience for visually inspecting test results when not using the Testable Component or Test Suite indicators.

For convenience, a report may be generated from the TestResult.

test.transaction Test Results
Test:TestCrossUsePacketTransaction(0 sec)
    Errors:Yes
    Messages:
        Packet was not handled

Clone this wiki locally