SiebUnit - Build Inventory

This article is a continuation on SiebUnit - an xUnit implementation, and provides an inventory of the parts needed to construct a SiebUnit framework.

Like the first article, this is aimed at the Technical Architect, who understands the concept, and knows how to put the necessary pieces together to bring this idea to life.


Architecture



The architecture diagram allows us to visualize important concepts at a high level, and can be used to break up big jobs into more manageable pieces.


Rules Engine

You can replace Rules Engine with any Siebel interface that supports receiving Inputs and returning Output PropertySets. SiebUnits will also work against a standard invoked business service, or workflow.

The only caveat is that you cannot have context, that is, you must re-design your BS/WFs to decouple your logic from any specific Application context. This naturally suits the testing of a rules engine, external API such as ESB, internal APIs like custom business object libraries, and scripting utilities.


SiebUnit Framework

A SiebUnit framework can be composed of the following sub components

* Test Case Runner
* Test Case start up routines
* Test Case tear down routines (optional)
* Test case assertion
* Random data generator
* Expression language
* Expression language parser
* Expression Executor
* Expression Builder
* Test history and performance timing
* Script Library
* Business Object (BO) Library
* XML Parser
* SQL/IO Layer


Test Case Runner

This component reads the configuration data from the data store, loads all the test cases in memory, and runs each test case one by one. It records start, stop times, and logs the output, but does not make any determination on the test case result. Errors are captured, and any exceptions are suppressed, allowing the Test Case Runner to continue on until it completes all test cases.


Test Case Startup/TearDown

In order to test certain scenarios, prerequisite test data may need to be setup before the rules can be tested. This component constructs the initial test data before the test suite runs. Optionally, there can be a Tear Down component, which cleans up after all test cases.


Test Case Assertion

Assert is a computer science term used to ensure a condition is true/false to enforces application integrity. The assertion component performs the same role, it checks the outputs of each test case, and validates it against the expected result for that test case, logging the result to a history data store.


XML Parser

This component converts XML into a structured object and back. This can be used to send dynamic outbound messages, and validate inbound responses, for integration testing.

SQL/IO Layer

This component retrieves the related data from an entity for validation purposes. It is used by the Test Case Assertion component.


Random Data Generator

Even within predefined test boundaries, we can allow the generation of random data to simulate dynamic conditions.

Eg. Generate a bunch of expense activities of random type, and amount, and test it against a business rule for assignment or approval logic.

The random data generator can be used by the Setup component, or the individual test case to randomize inputs into a rule.


Expression Language

To make SiebUnits declarative, we need a way of allowing the developer to construct data, supply dynamic inputs, and validate the results of the test cases, without writing a line of code. This can be done via an Expression Language, similar to calculated field expressions in Siebel.


Expression Language Parser

This component is responsible for translating the above expressions into a form which is understandable by the Siebel eScript compiler or external engine, that will in-turn run the instructions.

The expression parser needs to differentiate between a literal and expression. This is done via 4 ways, as illustrated throughout Siebel.

1. Field Pre/Post Default

Expressions need to be prefixed with "Expr: " or a key word such as "System", "Field" etc. Anything else is considered a literal.

If you wanted to pre default another field via the square bracket notation "[Id]" this will actually result in a literal value

2. Calculated Field

A calculation is always expected to be an expression, unless it is surrounded by quotes. So the square bracket notation "[Id]" is treated as an expression in this context.

3. Field Type

This example can be seen in WFs in the Output argument of some steps. There is another field that indicates the type. Eg: Literal vs Expression.

4. Dot Notation

WFs also have another interesting expression, with the dot notation to reference child elements within property sets. This dosnt really fit into either of the above 3 categories. As it can easily be interpreted as a literal, and does not have any prefixes to indicate that it is an expression.

You have to make a call on which method you will use, and your expression parser has to recognise the above patterns if you mix the scenarios.

Eg 1. For an eScript implementation, the expression

"GetProfileAttr('Me.Id')"

Should translate this to an eScript call like this

TheApplication().GetProfileAttr("Me.Id")

The parser has to recognise that this is an expression with a literal argument.


Eg 2. The next expression provides a dynamic input.

"GetProfileAttr([&Property])"

This follows Siebels WF standard, of referencing WF properties via the ampersand prefix inside square bracket notation, requires a bit more work because you have to deal with the nesting of expressions.

This is where you can draw the line, and define styles for your expressions and have another expression to deal with that scenario

"GetProfileAttrByProperty('Property')"

Now the literal references a property that holds the value to this method. You will have to plan out your expression language in advance, and know how your parser will deal with each scenario.


Expression Executor

After you've translated the expression into the native language, it needs to be executed, and the result returned. The method that you execute the expression, will impact on the style of your expressions, and how complex your parser needs to be.

Consider implementing a short circuiting mechanism so that, if part of a condition expression is met, you can abort executing the rest of the expression.


Expression Builder

This component allows the developer to choose from a defined set of expressions, this aids in learning, reduces mistakes, and as well as documenting all the supported functions of SiebUnit. Ideally It has to integrate with the Siebel UI session, and apply the expression to the list/control.


Test History and Performance timing

This data is produced by the Assert component which validates the test case runners run history with the expected outputs, it also extracts performance timings for analysis.

Inputs and Outputs of the run are also included in the run history to help debugging. Having the results in the UI is consistent of the expectations of a declarative tool. Take note BRP engineers!

Test history and performance data can be transient, and the user can export the results, if a base line needs to be established.

Script Library and BO Library

It is important to differentiate between the above two components. A script library provides utilities, and prototypes on native objects, while a BO library provides business functions.

A SiebUnit library is tightly integrated with the script library for performing internal operations, and provides proxy functions for invoking the BO library to setup and perform test cases. When creating framework functions you will have to make conscious decisions in which library a function belongs to.


Unit Testing and Regression Testing

SiebUnit does not replace commercial regression testing suites. An important differentiation is that SiebUnits is designed to be used by developers for unit testing code/WFs before it is checked in, and to ensure application integrity is maintained before it reaches the testers.

SiebUnits are also more thorough, as only the developer could understand all the exception paths of a program. SiebUnits test technical functionality, while regression test tools test functionality.

Although SiebUnit can be used to regression test business rules, it does not test UI components. The developer is still expected to ensure that UI rules are unit tested. A badly configured link, can still bring the system down and while writing SiebUnits to create data, and check the data returned from the link could be a valid test case. It was not intended to micro manage every piece of individual configuration.

SiebUnits can offer a great sense of security for the developer, but poorly designed test cases, can also provide a false sense of security. This is normally due to poor test case coverage. Average developers will usually test the positive scenario, good developers test both positive and negative scenarios. SiebUnits require the developer to understand all the possible logic paths and design test cases to thoroughly cover off the scenarios that can result the program to fail.

Conclusion

There are numerous benefits to having SiebUnits on a project. The immediate return on investment, is that your testing period is reduced, and your application will be more robust, but the real payoff of really comes down the track, when you build highly complex systems, where one small change can break another part of the system. SiebUnits can provide your developers with confidence to make that change, without costly regression testing. SiebUnits will keep your Application, and also your sanity in check.

xUnits is a proven concept, and is a staple of any modern development platform. SiebUnit provides an evolution path, so that your developers no longer need to manually unit test. The world has JUnit , jsUnit, CUnit, OCUnit, PHPUnit, PyUnit, SUnit and now we can add SiebUnit to the list.

SiebUnit - an xUnit implementation

Introduction

Over a year ago, I presented a concept of xUnits in Siebel and how they could be used. Because it was only a concept, it was missing implementation details, so there was some doubts to whether Test driven development would work in Siebel, where code is meant to be restricted to fringe cases.

At that time, I ported some code from a back end Java project that I was working on, to automate Siebel interface verification. The idea was to pickup XML templates from a file system, insert randomize data, send it to the ESB, and validate the results.

It was used for several releases, reducing a days worth of effort to verify 50 interface interactions, to about 5 minutes. With the JUnits in place, they could be used to verify an integrated environment instantly on demand, instead of employing highly paid professionals to perform repetitive regression testing.

The tool was written in Java, didnt have a UI, it had access to the eApps SSO hashes, which meant that an evil developer could use it to log onto a server environment, and impersonate anyone they wanted. It was more of a regression testing tool than a unit test tool, and being written in Java, it was inaccessible to most of the Siebel Team.

In the spirit of a true Siebel developer, I thought a real implementation of xUnits in Siebel had to be scriptless.

So "SiebUnit" was designed to be just that, a fully declarative unit testing framework for Siebel developers.

This framework also happens to plug into a rules engine like BRP, OPA, or it could be run against a collection of business services/workflows, as long as you can pass in an Input and get an Output property set, the "SiebUnit" framework handles the rest.

This idea was sold to a Client, who immediately picked it up as a way to get developers to unit test, improve build quality, and reduce dependence on testers, and provide a structured development process.

This article and its followup, takes a step further, providing architectural and implementation concepts. It is aimed at the Technical Architect, who can grasp high level concepts, fill in the low level implementation, possibly innovate on this idea, and introduce SiebUnits into your Siebel project.


What is SiebUnit

If you had to sell the concept of xUnits in Siebel, this slide should sum it up.



This screenshot shows a SiebUnit implementation that was built for a Client.



Features

Notification System for test results

Uses a custom notification system, written in a client side library, to add persistent messages to the current view. The messages can be dismissed, by clicking the X button.


Design and Run Test Cases from the UI

Test Cases are configured, executed and debugged all within a standard Siebel UI. Debugging the rules itself, depend on the capability of the rules engine. Eg. BRP can only be debugged via log files, WFs can be debugged using the instance monitor.


Export/Import test Cases

Allow easy export and import of hierarchical test configuration data between different environments.


Trace Toggling

Toggles developer tracing, for performance testing of rules


Dynamic test data

Uses XML templates, and proxy functions to the BO Library to generate unique test data. Random data can be generated and provided on inputs, or overridden in the case of XML templates.


Expression Builder

A helper utility designed for the developer to construct the test cases declaratively. This is built using HTML, which integrates with the Siebel session.


Other

SiebUnits comes with pre built internal test cases to validate your eScript engine, and profiles ST objects vs non ST objects.

SiebUnits can be configured to run recursively to load test an environment


Case Study - Custom Rules Engine

SiebUnits was used on a project to ensure the integrity of a Rules Engine.

The design of the custom rules engine started off in small components, followed by unit testing, further build and some more unit testing. The components were then integrated, followed by another round of unit testing.

As the design got exponentially more complex, the integration of all these components, made it impractical to regression test all the exception paths, after every change.

SiebUnits was originally built with integration to BRP. So for this project, it was modified to work with this new engine.

A collection of SiebUnits was built to test the following aspects.

Declarative IF conditions
Declarative loops
Declarative procedures
Expression Translation
Expression Results
Business Service Invocations
Property Assignment
Cancel Propagation
Error Messages
Math Operations
Rule inheritance
PropertySet Interactions


Some further internal test cases were also designed to validate the behaviour of the eScript engine. This ensures that if Siebel changes the eScript engine, these internal SiebUnits will pick up on the expected outputs of dependent core functions, and allow the root cause to be addressed.

Once the SiebUnits were designed, and configured, they were used to repeatedly validate the Rules Engine after every change, to ensure previously built functionality still functioned. Changes often broke other unexpected parts of the engine, due to the tight integration and dependency between components, but with the SiebUnits in place, the report of failed test cases helped to quickly pinpoint the cause.

Towards the end of the build, a critical defect was discovered with the eScript engine, that corrupts a core object of the rules engine. This happens during random runs of the test suite, but it was easily reproducible using the load runs.

The problem required a re-design of the core object, which unfortunately touches every function in the engine. Since the new object had a different interface to the old object, it required a re-design of most of the interactions around this object as well.

The affected parts of the program was identified, and a fix was implemented in two hours. The SiebUnits test suite was run afterwards to ensure that the rules engine passed all the test cases. This provided a QA stamp on the product, and was similiar to having a team of regression testers on hand to validate your work at will.

The collection of SiebUnits also allowed load testing of the engine in a real environment. During these load runs, server resources can be monitored to ensure that they run within acceptable standards and allow capacity planning based on expected usage.

It would have been much more difficult if not impossible, to complete such a complex build without SiebUnits in place, and the regression testing and maintenance effort would have been an ongoing burden.


Intermission

Do you have BRP, OPA or a collection of Business Services that you would like to keep in check? The next article will look at the architecture of SiebUnits, and all the components that need to come together to form the framework of SiebUnit.

Note: The term Rules Engine is used broadly in this article. Even though BRP stands for Business Rule Processor, it is actually a declarative eScript replacement engine. OPA is more suited to the term for a Rules Processor, as it takes a bunch of inputs, makes a determination and returns the result. However the Rules Engine interface of Inputs/Outputs is what makes it suited to SiebUnits.

View the next article here