(Classic) Test-Driven Development and KRL

This page described a way to do TDD in the Classic pico-engine. It needs to be updated to work with pico-engine 1.X.

General Setup

The general setup for doing TDD with KRL on SquareTag is as follows:

  • Create an account for doing the testing. 

  • Ensure it's CloudType is set to developer (See the (Classic) Quickstart for SquareTag for more information)

  • Install the Kynetx Developer Kit (KDK) and Test Module from the AppStore. 

  • Install any other modules and rulesets necessary for the testing. These generally include the ruleset being tested and the ruleset that contains the tests. (note: more than one ruleset and testing ruleset can be installed in an account.)

  • Use the KDK to get an ECI for configuring the tests (see Test Harness below)

Tools

There are several tools that make TDD easier with KRL. 

Test Module

The test module provides functions, actions, and rules for doing TDD in KRL. The code for the module is located on Github and is registered as ruleset b503129x0 on the Kynetx-hosted instance of KRE.

The module provides the following actions

  • diag() - returns a directive with status set to "diagnostic". 

The module provides the following rules:

  • see_success - selects on test:succeeds and returns a directive with  status set to "success" along with other information about the result. 

  • see_failure - selects on test:fails and returns a directive with  status set to "failure" along with other information about the result. 

Test Harness

The test harness is a perl program that raises appropriate events to a test account interprets directives from the test module. The code for the test harness is located on Github

The test harness uses a test configuration file to know what tests to run. The 

test config file looks like this:

# cloudos_test@kynetx.com/for_testing eci: 07E6569E-6CE9-11E3-81D7-05AFD88E7806A rules_engine: kibdev.kobj.net rids:  - b16x44 test_1: desc: "AWS Module Test" domain: test type: store_item attributes: foo: bar rids: - b22342x1.prod

The eci is a channel to a pico where the test rulesets, the rulesets to be tested, and the test module ruleset have been installed. If no ECI is given, then the event is raised with the Blue event API, otherwise the Sky event API is used. 

The rules engine will default to kibdev if not specified.  

The rids array specifes a RID list for all the tests. Rid specifications in each test can override the general delcaration. 

Each test is in a structure with a name that starts with test_.  And structure with a name with that prefix will be run. In this case, there’s just one that raises the event test:store_item.  You can add attributes.  If a rids array is present the event will be raised for those rids rather than generally to all installed rulesets. 

Writing Tests

Tests look like rulesets. In general, rules in the ruleset can be used to set up the test and check whether or not it succeeded. Here are a few hints for writing rules that act as tests:

Include the Test Module - The test ruleset should use the test module in its meta block. I give it the alias show_test so that actions I use from it are easy to find. 

use module b503129x0 alias show_test

Use the test domain so that test rules only fire during tests - the test event domain can be used to namespace test events so that test rules don't fire for other reasons. 

Include a test_desc variable in the prelude with a description of the test - the value of the variable can be easily included with the test response. 

Write the test as a rule condition - the test itself is the rule condition. The prelude can be used to do any calculations necessary to perform the test.

Always use a diagnostic action in the rule - Rule actions don't have alternate. That is, there's no else. Therefore, make the rule action a diagnostic message with as much detail about the intermediate calculations as you find helpful.

Raise test:succeeds and test:fails events in the postlude of the rule - The fired { } else { } postlude construct can be used to raise a test:succeeds and test:fails depending on the result of the test in the rule condition. The see_success and see_failure rules in the test module will respond to these events and issue the appropriate directives. 

Like any testing exercise, you will find that the testing process goes easier if you write your code with testing in mind and build tests as you go. Sometimes, you will have to build functions, actions, or rules into your code just so that you can test certain features of your ruleset. 

Example

The following two rules test the request token response in the Dropbox module. The first rule, get_request_token_test is selected on test:get_request_token. The first rule doesn't perform a test, but rather sets it up. The action dropbox:get_request_token autoraises an http:post event when the action is performed. 

rule get_request_token_test { select when test get_request_token pre { values = {'tokens' : my_tokens, 'header' : dropbox:return_header(my_tokens) }; } if(not authorized) then { dropbox:get_request_token(); show_test:diag("test initiation", values); } }

The second rule, process_request_token, responds to the http:post event, processes the HTTP response by decoding the content to retrieve the tokens, and tests the tokens to ensure they aren't empty. 

Note that this rule raises test:succeeds or test:fails events depending on whether the condition is true or not. These events trigger the rules in the test module so that the proper directives are returned to the test harness. At present, the details of raising test:succeeds or test:fails events cannot be hidden because the postlude doesn't support any abstraction mechanisms. 

The test configuration file to run this test looks like this:

If the Test module, Dropbox module, and Dropbox Test ruleset are installed in the pico pointed to by the ECI in the test configuration file, then running the test harness produces the following output:

The test harness also supports the verbose (v) switch that prints our the success and failure messages:

With the detail (d) switch added to the verbose (v) switch, the detailed logging information is also printed out:

Note that the detail (d) switch combined with the operation of the diagnostic action in the Test module makes it relatively easy to see intermediate values to determine why things may not be working as planned. 



Copyright Picolabs | Licensed under Creative Commons.