Skip to end of metadata
Go to start of metadata

In This Chapter

 

Servoy has built-in support for Unit Testing. The integration adds the following to the Servoy Developer environment:

  • A JSUnit node to the Solution Explorer, exposing the assert functions used in testcases
  • An entry in the context menu (of the active solution, active modules, forms or solution scope nodes) in Solution Explorer View to run the Unit Tests
  • A JSUnit view for viewing the results of a test run

 

testXYZ methods

Creating testcases is as straightforward as creating a function with a name that is prefixed by 'test_':

 

function test_thisShouldPass() {
 jsunit.assertEquals('This test should pass', true, 5 < 10);
}

function test_thisShouldFail() {
 jsunit.assertEquals('This test should fail', true, 10 < 5);
}

The JSUnit node in the Solution Explorer provides easy access to the different supported assert functions

Testcases can be added on application level in the global scope of on form level in the form scope.

setUp & tearDown methods

Each scope can contain a setUp and/or tearDown function. The setUp function is called BEFORE running each testcase in the scope and the tearDown function is called AFTER running each test in the scope. The setUp and tearDown function allow the developer to create the right circumstances for testcases to run and cleanup afterwards. Note that the setUp() and tearDown() methods are called before and after EACH test methods, as each single test is supposed to be independant.

 

Example
function setUp() {
  //Code here to setup the environment for the testcases in this scope
}
function tearDown() {
  //Code here to cleanup the environment after running the testcases in this scope
}

 

Testing Asynchronous Code

When testing asynchronous code, for example a queued method using the queueMethod method of the Headless Client plugin with a notifyCallback method or a executeAsyncRequest on the HTTP plugin with a success/errorCallback and the UnitTest needs to test the result of the callback method, application.updateUI(Number:milliseconds) can be used inside a loop to wait for the callback to be invoked and test it's result.

Asynchronous UnitTest template
/**
 * @type {Number}
 */
var TIME_OUT = 1000

/**
 * @type {Number}
 */
var UPDATE_WAIT = 100

var callbackReceived = false

/**
 * @type {Object}
 */
var callbackRetval

function testLocalLinkCallback() {
	callbackReceived = false
	//Your code here that invoked something that used testCallback as callback method
	var it = 0
	while (!callbackReceived && it < TIME_OUT / UPDATE_WAIT) {
		application.updateUI(UPDATE_WAIT);
		it++
	}
	if (!callbackReceived) {
		jsunit.fail('callback not invoked within TIME_OUT period')
	} else {
		//Check the content of callbackRetval here using jsunit.assert*
	} 
}
 
function testCallback() {
	callbackReceived = true
	callbackRetval = //Store whatever you need to complete your test in calbackRetval

 

assertEquals vs. assertSame

The jsunit object supports 2 methods that seem similar, but have a distinct difference: assertEquals and assertSame. The difference between these two function is the JavaScript compare operator they use:

  • assertEquals uses the '==' equal operator
  • assertSame uses the ' ===' strict equal operator

The difference between these two operators is that the equal operator does type conversion if the objects on both sides of the operator are of different types, while the strict equal operator does not.

Example
jsunit.assertEqual(1,'1') //true
jsunit.assertSame(1,'1') //false


Security (non-mobile solutions) and plugin usage

Although simulating a user login is not supported for unit tests via before-solution-load settings (this also means that your test solution shouldn't have login/authenticator solutions nor should it have 'mustAuthenticate' checked) it is still possible that when your tests begin running (for example in the solution onOpen) you simulate one or another user being logged in through the security JS api (the internals of which are modified a bit for the test clients):

Simulating a user login inside the test solution
security.authenticate(null,null,["admin","admin"]); // this assumes you have the admin user available

You can use these API calls for example in setUp/tearDown methods as well. You could authenticate and create/delete user groups in setUp (and do whatever else is needed) and in tearDown you could do:

Preparing to login with another user
security.logout(); // for test clients this has a special implementation;
                   // it doesn't close the solution, just allows you to
                   // authenticate again with another user afterwards

Being able to simulate log-in is also useful because access to some plugins is limited to authenticated usage. For example if you want to use the headless plugin you might want to authenticate first.

About solution load / onOpen handler & jsunit

When unit tests are being ran, the test client will wait for the solution to load before starting to run unit tests.

This means that:

  1. "jsunit" is not available in scripting during solution "onOpen" handler execution;
  2. the solution could fail to load or take a very long time to load due to code executing in "onOpen" handler; there are default timeouts when waiting for a test solution to get loaded. If your solution really needs more time to execute "onOpen" then you should modify those default load timeouts as shown below:
    • developer (non-mobile test client) tests: in Developer Preferences go to Servoy; at the bottom of that page you will see a Launcher settings section where you can modify the timeout value.
    • developer (mobile test client) tests: in the launcher configuration page (toolbar dropdown of green play button -> Organize...) you can modify the timeout value.
    • for automated test environments the unit test client (both mobile and non-mobile) timeout values can be configured via command line arguments; see Command line utilities for Solution Exporting and Unit Testing..., argument servoy.test.solution-load.timeout.


  • No labels