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:
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:
I hope you found this demo of how to test FE functions useful. Thank you for reading!