GDPR Cookie Consent by Free Privacy Policy Generator
post thumb
Asset Control
by Matthias Hanitzsch-Moonlight/ on 21 Mar 2018

Integration Testing - Formula Engine

Here, I demonstrate how to use the Basic Java API and JUnit to write an integration test for a Formula Engine function.

Test function

For this demo I deliberately choose I simple FE test function: A check to see if an input string starts with a given prefix.

I have created this function as part of a formula stored in Asset Control as this makes it easy to load and run:

TFN_LIB

Some might say that the following test hardly qualifies as an integration test. However, I believe this simple example lets me focus on the tooling and general pattern I want to demonstrate. Other articles in this series then focus more on the integration aspect.

Now, let’s see how I can test this function.

Test implementation

The test implementation is based on the Basic Java API (which relies on the Asset Control Java API), JUnit 4 and the Hamcrest library (for assertions and matchers). If you use Maven, you could add the following dependencies to your project:

  <dependency>
      <groupId>asset-control</groupId>
      <artifactId>ac-server-api</artifactId>
      <version>4.4.27</version>
  </dependency>
  <dependency>
      <groupId>io.terrafino</groupId>
      <artifactId>ac-api-basic</artifactId>
      <version>1.0.0</version>
  </dependency>
  <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
  </dependency>
  <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest-all</artifactId>
      <version>1.3</version>
      <scope>test</scope>
  </dependency>

The implemented test then looks as follows:

package io.terrafino.ac;

import io.terrafino.api.ac.AcException;
import io.terrafino.api.ac.service.AcConnection;
import io.terrafino.api.ac.service.AcService;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

public class StartsWithIntegrationTest {

    private static AcConnection conn;
    private static AcService ac;

    @BeforeClass
    public static void setUp() throws Exception {
        conn = AcConnection.getDefaultConnection();
        ac = new AcService(conn);
    }

    @AfterClass
    public static void tearDown() throws Exception {
        conn.disconnect();
    }

    @Test
    public void returnsTrueForMatchingPrefix() throws Exception {
        ensureCallReturns("startsWith('abc', 'a')", "1");
    }

    private void ensureCallReturns(String feCall, String expected) throws AcException {
        String formula = String.format("load('TFN_LIB', 'TABLE'); return %s;", feCall);
        List<List<String>> res = ac.executeFormulaEngineQuery(formula);
        assertThat(res.get(0).get(0), is(expected));
    }
}

Here is a breakdown of the above code:

  • I have implemented a class StartsWithIntegrationTest
  • As I want to connect to AC and execute Formula Engine code, I need instances of AcConnection and AcService.
  • The setUp method annotated with @BeforeClass will be executed once before running all the test functions within the class. So, this is the right place to open a connection to AC and initialise the AcService with it.
  • The tearDown method annotated with @AfterClass will be executed once after running all the test functions. Here, I disconnect from AC.
  • Any method annotated with @Test represents a test. The name of the method should communicate what the tests does and/or what the expected outcome is.
  • By introducing the method ensureCallReturns I can keep the code within my test functions very short, only keeping the essential parts.
  • Within ensureCallReturns I construct the complete Formula Engine code to load the formula TFN_LIB and call the given function.
  • I then use an assertThat statement to check the actual result of the FE call against my expected result.

You can then think of other scenarios you want to test, e.g.:

    @Test
    public void returnsTrueForEmptyInputAndEmptyPrefix() throws Exception {
        ensureCallReturns("startsWith('', '')", "1");
    }

    @Test
    public void returnsFalseForEmptyInputAndNonEmptyPrefix() throws Exception {
        ensureCallReturns("startsWith('', 'abc')", "0");
    }

    @Test
    public void returnsTrueForEmptyPrefix() throws Exception {
        ensureCallReturns("startsWith('abc', '')", "1");
    }

    @Test
    public void returnsFalseForNonMatchingPrefix() throws Exception {
        ensureCallReturns("startsWith('abc', 'x')", "0");
    }

If I execute this in IntelliJ IDEA, I see the following:

StartsWithIntegrationTest Result

I hope you found this demo of how to test FE functions useful. Thank you for reading!

comments powered by Disqus