Unit Testing

ISL Unit Testing

The ISL unit testing framework lets you write and run tests entirely in ISL. Tests live alongside your transformation code, use the same syntax, and can verify behavior without learning a separate testing language.

Quick Start

  1. Create an .isl file with @test-annotated functions:
@test
fun test_simpleAssertion() {
    $value: 42;
    @.Assert.equal(42, $value);
}
  1. Run tests from the command line:
isl test
# or specify a path
isl test tests/
isl test tests/sample.isl
isl test tests/calculator.tests.yaml   # YAML-driven suite
  1. Or run tests programmatically from Kotlin/Java (see Test Setup).

Two Ways to Define Tests

  • Annotation-based – In .isl files with @setup and @test (see Test Annotations).
  • YAML-driven – In *.tests.yaml files: specify setup.islSource, optional mocks, and a list of tests with functionName, input, and expected. No ISL test code required. See YAML-Driven Test Suites for the full format, including assertOptions and mockSource/mocks.

What You Can Test

  • Transformations – Call your ISL functions and assert on the output
  • Conditions – Verify branching logic, edge cases
  • Modifiers – Test | trim, | map, | filter, etc.
  • External integrations – Use mocking to replace @.Call.Api and similar

File Format and Structure

Tests are written in standard .isl files. A test file typically contains:

  • One optional @setup function (runs before each test)
  • One or more @test functions (each is a test case)
@setup
fun setup() {
    $x: 1;  // Shared setup runs before each test
}

@test
fun test_basic() {
    @.Assert.equal(1, 1);
}

@test("Custom display name")
fun test_withName() {
    @.Assert.equal(2, 2);
}

@test({ name: "Grouped test", group: "math" })
fun test_grouped() {
    @.Assert.equal(3, 3);
}

File discovery:

  • CLI: isl test finds all .isl files (by default **/*.isl) containing @setup or @test
  • API: You pass the list of files to TransformTestPackageBuilder

Attributes (Annotations)

Attribute Description
@test Marks a function as a test. Runs as a test case.
@test("Name") Same, with a custom display name
@test(name, group) Custom name and group for organization
@test({ name: "x", group: "y" }) Object form for name and group
@setup Marks a function to run before each test in the file (at most one per file)

See Test Annotations for details.

Assertions

Use @.Assert to verify values:

Assertion Description
@.Assert.equal(expected, actual, message?) Deep equality (objects, arrays, primitives)
@.Assert.notEqual(expected, actual, message?) Values must differ
@.Assert.notNull(value, message?) Value must not be null
@.Assert.isNull(value, message?) Value must be null
@.Assert.contains(expected, actual) actual contains expected
@.Assert.matches(pattern, value) value matches regex
@.Assert.startsWith(prefix, value) value starts with prefix
See Assertions for the full list

Loading Test Fixtures

Use @.Load.From(fileName) to load JSON, YAML, or CSV files relative to the current ISL file:

@test
fun test_withFixture() {
    $data = @.Load.From("fixtures/input.json")
    @.Assert.equal("expected", $data.name)

    $config = @.Load.From("config.yaml")
    @.Assert.equal(10, $config.count)

    $rows = @.Load.From("fixtures/data.csv")
    @.Assert.equal(2, $rows | length)
}

Supported formats: .json, .yaml, .yml, .csv (all converted to JSON). See Loading Fixtures.

How to Run Tests

isl test [path] [options]
  • path: Directory, single file (e.g. sample.isl or suite.tests.yaml), or default: current directory
  • --glob PATTERN: Filter .isl files when path is a directory (YAML suites use **/*.tests.yaml when not set)
  • -f, --function NAME: Run only tests whose function name matches; use file:function for a specific file (e.g. sample.isl:test_customer or calculator.tests.yaml:add)
  • -o, --output FILE: Write results to JSON

Programmatic (Kotlin/Java)

See Test Setup for adding the isl-test dependency and running tests from code.

Mocking

Mock external functions (e.g. @.Call.Api) so tests don’t hit real services:

@test
fun test_withMock() {
    @.Mock.Func("Call.Api", { status: 200, body: "ok" })
    $result = @.Call.Api("https://example.com")
    @.Assert.equal(200, $result.status)
}

See Mocking for parameter matching, indexed (sequential) returns, loading mocks from files, captures, and annotation mocks.

Test Output

  • CLI: Prints pass/fail per test, with failure messages and locations
  • JSON: Use -o results.json for machine-readable output
  • Exit code: 1 if any test failed, 0 if all passed

Next Steps