Skip to main content

Version: 17.10 (EOL)

Unit Testing Guide

Transact provides good support developing automated unit tests for Groovy services and functions.

Whenever you are developing services and functions you must build corresponding unit test code to ensure your business logic works correctly. Developing unit test coverage is critical the successful delivery of Transact applications. Unit tests provide the following critical functions in Transact solutions:

  • verifies that business logic executes correctly
  • verifies that error handling logic functions as expected
  • enables the business to continually deliver application improvements into the market without having to go expensive and through time consuming manual testing processes
  • enables Transact systems to be upgrade to the latest versions or receive security patches and automatically verify whether there are impacts or regressions
  • supports modern software development best practices

To develop your services business logic you should write unit test code to execute your Groovy script under a variety of test scenarios. If you develop your services in this way you will be more productive and can develop much more robust code. Unit Tests enable you to exercise Groovy services in ways which are really difficult to produce manually.

Transact Unit Testing Features

Transact provides a number of important features to support services and functions unit testing these include:

  • Groovy Service and Function Unit Test templates to get developers started immediately
  • Mocking Libraries
  • JUnit4 Support
  • Ant and Maven based CI build support
  • IntelliJ and Eclipse IDE unit test execution support

JUnit4 Library Support

Support for JUnit4 test annotations enables developers to write service unit tests that can be executed both locally and remotely on a TM server.

  • If you need unit tests that can run locally and on TM servers then subclass AbstractJUnitTest, but these unit tests will not support IDE debugger sessions.
  • If you want unit tests that can be run directly in your IDE debugger, your tests will need to subclass TransactSDKUnitTest, but these unit tests cannot be executed on the TM server (because of dependency injection constraints).

Supported JUnit4 annotations include:

@BeforeClassSpecifies method to be called once when test class in setup
@BeforeSpecifies method to be called before each test method invocation
@TestSpecifies test method to be invoked
@AfterSpecified method to be called after each test method invocation
@AfterClassSpecifies method to be called once when test class is finished
@IgnoreSpecifies test method that will not be executed

Test Coverage

Typically your service unit test code should incorporate many @Test case methods to executing different scenarios to ensure you have adequate test coverage. A multi-test method unit test is provided below.

 public class GetAccountsTest extends TransactSDKUnitTest {
void testOk() throws Exception {
// Test normal service call
void testBadRequest() throws Exception {
// Test HTTP 400 bad request
void testServiceUnavailable() throws Exception {
// Test HTTP 503 service unavailable

Mockito Library Support

Transact includes support for the Mockito unit testing mocking framework. This library is included in the Fluent SDK distribution and has been added to the Secure Compiler Whitelist for unit test execution.


The Mockito library is not whitelisted for production execution as it provides extensive reflection and interception methods that could compromise the Fluent services security model.

Mocking VO Constructors

The Fluent Value Object (VO) classes provide immutable value objects for core TM entities represented in the database. You can create these mock objects using the VO constructors which take a map of field attributes. This enables you to mock VO classes without having to execute your unit tests in a TM server.

An example mock Txn object is shown below.


// Unit Test Code
Map fields = [
"id": new Long(123),
"formCode": "CCA-FTX",
"userSaved": true

Txn tx = new Txn(fields)

For security reasons, the VO map constructors are not permitted in production code execution.

Mocking HTTP and Service / Function Calls

Transact provides a MockRegister class that supports testing your service code with mock responses for external services calls when executing in a unit test context.

MockRegister supports mocking responses for calls of the following classes.

  • HTTP GetRequest, PostRequest, PutRequest, DeleteRequest, and PatchRequest
  • GroovyServiceInvoker
  • FluentFuncInvoker
  • ServiceInvoker

Test mocking is an important practice in modern software development as it enables you to:

  • test service code in isolation from other components
  • develop your service code before other services are available
  • test error handling modes which are difficult to achieve when calling real services
  • test in environments where external services may not be available; for example, a dev machine or CI server
  • build CI tests to execute much faster than when calling external services

MockRegister registers a mock response object in a thread local store which Transact will return when executing services code in a unit test context. This works as follows.

  1. Unit test code registers mock response for an external service call.
  2. Unit test code then calls service's invoke method.
  3. The invoked service now calls an external service.
  4. Transact finds a matching registered mock request object and returns the associated mock response object.
  5. Service code receives mock response object and performs its logic.
  6. Unit test code verifies that service code performed correctly for the given execution context.

To illustrate this see the concrete example HTTP service code below.

Mocking HTTP Calls

In this example we are developing a GetAccounts service which makes a HTTP request to an retrieve a list of accounts. The HTTP endpoint configuration details are provide by the services SvcConn object. If the HTTP call does not return a 200 OK status code then our service will return a validation error to the form.

 public class GetAccounts {
public Logger logger
FuncResult invoke(FuncParam param) {
SvcConn svcConn = param.svcDef.svcConn
HttpResponse response = new GetRequest(svcConn.endpoint)
.setBasicAuth(svcConn.username, svcConn.password)
FormFuncResult result = new FormFuncResult()
if (response.isStatusOK()) { = response.getTextContent()
} else {
result.errors.add(new ValidationError("accountsSvcError"))
return result

Now, to test our service's handling of HTTP errors, we will mock a HttpResponse object returning a HTTP 503 Service Unavailable error. This response object is registered using the same GetRequest object that is used in the service call. Transact's mock object matching rules are discussed later.

 public class GetAccountsTest extends TransactSDKUnitTest {
void testFunction() throws Exception {
FuncParam funcParam = new MockVoBuilder().createFuncParam(TRIGGER_FORM_UPDATE, svcDef, testParams)
// Create a matching GetRequest object
SvcConn svcConn = svcDef.svcConn
HttpRequest matchRequest = new GetRequest(svcConn.endpoint).setBasicAuth(svcConn.username, svcConn.password)
// Create a mock response object
HttpResponse mockResponse = new HttpResponse().setStatus(503)
// Register the request object to return mock response object when a matching HTTP request is made
new MockRegister().when(matchRequest).thenReturn(mockResponse)
// Invoke service
FormFuncResult result = (FormFuncResult) new ServiceInvoker(svcDef)
.invoke("funcParam", funcParam)
// Test results result
assert result.errors.get(0).errorKey == "accountsSvcError"

The key line in the code above is the MockRegister call which registers the HttpRequest object and associated mock response object.

new MockRegister().when(request).thenReturn(response);

HttpRequest.execute() checks whether there is a registered thread-local HttpRequest object which semantically matches the current HttpRequest object. If there is, the execute method will return the registered mock response object immediately and not perform the actual HTTP request.

HttpRequest Matching

When Transact is looking for a mock response object registered with a request, it tests the registered request object's attributes against the HttpRequest object that is executing currently. The attributes that are matched include:

  • matching - request method (GET, POST, PUT, DELETE)
  • matching - request URI
  • matching - request message data
  • mock request headers is a matching set or is a subset of actual request headers
  • mock request parameters is a matching set or is a subset of actual request parameters

Mocking Service / Function Calls

The other scenario where the MockRegister class is useful is when one service or function is calling another service and we need to mock the response of the second service or function. Service mocking is supported in the ServiceInvoker, FluentFuncInvoker and GroovyServiceInvoker classes.

To visualize this, consider the following execution path.

Trigger          ->  Service A
Service A -> Service Invoker
Service Invoker -> Service B
Service B -> returns response

To facilitate unit testing we use the MockRegister to skip calling Service B and instead return a test result object directly from the ServiceInvoker class.

Test Trigger     ->  Service A
Service A -> Service Invoker
Service Invoker -> return mock result

To illustrate this scenario, we've defined a PrefillFunction class which is calling the shared Groovy Service to look up some data from another system.

 public class PrefillFunction {
public Logger logger
FuncResult invoke(FuncParam param) {
Map params = [:]
params.request = param.request
String profileData = new GroovyServiceInvoker()
Map profileMap = new GsonBuilder().create().fromJson(profileData, Map.class)
FormFuncResult result = new FormFuncResult() = profileMap;
return result

To mock the Groovy Service call profileData result in our PrefillFunction unit test we register a mock result object with MockRegister. Note the registered service definition matches that used in the PrefillFunction code.

 public class PrefillFunctionTest {
public Logger logger
FuncResult invoke(FuncParam param) {
FuncParam funcParam = new MockVoBuilder()
.createFuncParam(FuncParam.TRIGGER_FORM_OPEN, Txn.FORM_SAVED, svcDef, testParams);
SvcDef matchSvcDef = new SvcDef([
"name": "LoadProfile",
"clientCode": svcDef.clientCode,
Map profileData = [
"firstName": "John",
"lastName": "Smith",
"email": "[email protected]"
new MockRegister().when(matchSvcDef).thenReturn(profileData)
// Invoke service
FormFuncResult result = (FormFuncResult) new ServiceInvoker(svcDef)
.invoke("funcParam", funcParam);
// Test results result
assert != null
assert == profileData

Service / Function Matching

The service or function being called is matched using the registered SvcDef attributes. The registered SvcDef should have the same attributes which are used in the service call. These attributes include:

  • name - the service name (required)
  • version - the service version number (optional)
  • clientCode - the service's organization client code (required)
  • parameters - the service parameters (optional)