Kompilator.no
situs

Like JUnit, but aimed at System Integration Testing.

An annotation-driven system integration testing library for Java 21 under the no.kompilator.situs namespace. Define SIT suites as plain Java classes, run them on demand via a REST API or programmatically, and get structured reports in JUnit XML, Open Test Reporting XML, or JSON.

Suites run at runtime in production-like environments instead of only at build time. They support Spring dependency injection, parallel execution, timeouts, delays, retries, and deterministic ordering.

Repository structure

How the project is split across core, plugins, and examples.

.
├── situs/                      Core library - annotations, engine, Spring integration
├── plugins/                    Ready-made plugins (reporting: JUnit XML, OTR XML, JSON)
├── java-spring-boot-sample-app/    Java Spring Boot example using the library
└── kotlin-spring-boot-sample-app/  Kotlin Spring Boot example using the library
Published artifacts

Maven coordinates that are currently published.

no.kompilator:situs
no.kompilator:plugins
Modules

Core artifacts, plugins, and sample applications.

ModuleArtifactDescription
situsno.kompilator:situsSIT annotations, execution engine, and HTTP API
pluginsno.kompilator:pluginsReporting plugin - writes structured test reports
java-spring-boot-sample-app-Java sample app (not published)
kotlin-spring-boot-sample-app-Kotlin sample app (not published)
Supported API surface

Build against these packages only.

no.kompilator.situs.annotations
no.kompilator.situs.model
no.kompilator.situs.plugin
no.kompilator.situs.service
no.kompilator.situs.spring
no.kompilator.situs.spring.model
Internal packages

These may change without notice.

no.kompilator.situs.domain
no.kompilator.situs.runtime

Quick start

Start with the core artifact, define suites as plain Java classes, and expose them through Spring Boot when needed.

1. Add the dependency
// build.gradle.kts
dependencies {
    implementation("no.kompilator:situs:2.0.0")

    // Optional - adds structured report writing (pulls in situs transitively)
    implementation("no.kompilator:plugins:2.0.0")
}
2. Define a test suite
@TestSuite(name = "CalculatorTestSuite", description = "Tests for Calculator")
public class CalculatorTestSuite {

    @Test(name = "addition", description = "2 + 3 should equal 5", order = 1)
    public void testAddition() {
        assertThat(2 + 3).isEqualTo(5);
    }

    @Test(name = "divisionByZero", timeoutMs = 500, order = 2)
    public void testDivisionByZero() {
        assertThatThrownBy(() -> 1 / 0)
                .isInstanceOf(ArithmeticException.class);
    }
}
3. Spring Boot - package-scoped discovery
@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

testframework.scan-packages=com.example.tests

Spring Boot auto-configuration is enabled automatically when the library is on the classpath. @EnableRuntimeTests is only needed for explicit opt-in in non-Boot Spring applications.

Useful Spring properties

testframework.scan-packages=com.example.tests
testframework.full-classpath-scan=false
testframework.max-stored-runs=200
testframework.reporting.enabled=true
testframework.reporting.output-dir=build/test-reports
testframework.reporting.formats=JUNIT_XML,OPEN_TEST_REPORTING_XML,JSON
4. Run tests via HTTP
# List all discovered suites
curl http://localhost:8080/api/test-framework/suites

# Start a suite run (async)
curl -X POST http://localhost:8080/api/test-framework/suites/CalculatorTestSuite/run
# -> {"runId":"abc-123"}

# Poll until COMPLETED
curl http://localhost:8080/api/test-framework/runs/abc-123/status

# Cancel a running suite
curl -X POST http://localhost:8080/api/test-framework/runs/abc-123/cancel
Key features

Core annotations and operational behavior.

FeatureAnnotation / API
Define a test suite@TestSuite
Define a test method@Test
Setup / teardown@BeforeAll, @AfterAll, @BeforeEach, @AfterEach
Parallel execution@TestSuite(parallel = true)
Deterministic orderingorder = ... on @Test, @BeforeAll, @BeforeEach, @AfterEach, @AfterAll
Timeout per test@Test(timeoutMs = 500)
Delay before test@Test(delayMs = 300)
Retry on failure@Test(retries = 2)
Spring DI in suitesAnnotate suite with @Component
Auto-discoveryPackage-scoped scan via testframework.scan-packages
HTTP APIBuilt-in REST controller via Spring auto-configuration
Run cancellationPOST /api/test-framework/runs/{runId}/cancel
Structured reportsReportingPlugin - JUnit XML, OTR XML, JSON
Incremental plugin hookSuiteRunListener#onTestCompleted(...)
Spring DI in test suites

Annotate the suite with @Component and inject dependencies through the constructor.

@Component
@TestSuite(name = "PaymentTestSuite")
public class PaymentTestSuite {

    private final PaymentService paymentService;

    public PaymentTestSuite(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    @Test(name = "chargeSucceeds")
    public void chargeSucceeds() {
        assertThat(paymentService.charge(100)).isTrue();
    }
}
Kotlin support

Use kotlin("plugin.spring") so @Component suites stay open for Spring proxying.

@Component
@TestSuite(name = "CalculatorTestSuite", description = "Tests for Calculator")
class CalculatorTestSuite(private val calculator: Calculator) {

    @Test(name = "addition")
    fun testAddition() {
        assertThat(calculator.add(2, 3)).isEqualTo(5)
    }
}
Reporting plugin

Automatic report writing or manual listener registration.

dependencies {
    implementation("no.kompilator:plugins:2.0.0")
}
testframework.reporting.enabled=true
testframework.reporting.output-dir=build/test-reports
testframework.reporting.formats=JUNIT_XML,OPEN_TEST_REPORTING_XML,JSON
ReportingPlugin reporter = ReportingPlugin.builder()
        .outputDir(Path.of("build/test-reports"))
        .format(ReportFormat.JUNIT_XML)
        .format(ReportFormat.JSON)
        .build();

testFrameworkService.addListener(reporter);

Reports are written automatically after every suite run.

Plugins can also observe per-test progress through SuiteRunListener#onTestCompleted(...).

Async status polling

Explicit progress and timing fields for long-running suites.

completedCount / totalCount for cheap progress tracking
runStartedAtEpochMs / lastUpdatedAtEpochMs on SuiteRunStatus
startedAtEpochMs / completedAtEpochMs on each TestCaseResult
status = CANCELLED when a caller stops a run explicitly
Validation rules

The framework fails fast during startup or registration when these conditions are violated.

suite names are duplicated
test names are duplicated within a suite
timeoutMs < -1
delayMs < 0
retries < 0
a @Test or lifecycle method is not public
a @Test or lifecycle method is static
a @Test or lifecycle method declares parameters
Deterministic ordering

Execution order stays predictable.

lower order values run first
ties are resolved by method name

Release, build, and test

Local publishing, parallel verification, and release publishing are all exposed through the Gradle wrapper.

Release

Local publish

./situs/gradlew publishAllToMavenLocal

Parallel multi-module verification

./situs/gradlew testAll
./situs/gradlew buildAll

Project-level parallel execution is enabled in gradle.properties, so independent subprojects run concurrently where Gradle can schedule them safely.

Remote publish credentials

centralUsername=...
centralPassword=...
signingKey=...
signingPassword=...

Equivalent environment variables

export CENTRAL_USERNAME=...
export CENTRAL_PASSWORD=...
export SIGNING_KEY=...
export SIGNING_PASSWORD=...
./situs/gradlew publishRelease
Release tasks and GitHub flow

Root release tasks

releaseCheck - runs tests and Javadocs for the releasable modules and sample apps
publishAllToMavenLocal - publishes situs and plugins to mavenLocal
publishRelease - runs releaseCheck and then publishes situs and plugins

GitHub Actions release flow

push a tag like v2.0.0
or trigger the release workflow manually with version
the workflow runs publishRelease with -Pversion=<tag>
required repository secrets: CENTRAL_USERNAME, CENTRAL_PASSWORD, SIGNING_KEY, SIGNING_PASSWORD
Build and test commands

Build everything from the repo root

./situs/gradlew --project-dir . build

Build a specific module

./situs/gradlew :situs:build
./situs/gradlew :plugins:build

Run tests

./situs/gradlew :situs:test
./situs/gradlew :plugins:test
Further reading and requirements

Modules - further reading

situs/README.md - annotations, runtime engine, Spring integration, full API reference
plugins/README.md - reporting plugin, report formats, configuration
java-spring-boot-sample-app/README.md - Java Spring Boot sample
kotlin-spring-boot-sample-app/README.md - Kotlin Spring Boot sample

Requirements

Java : 21
Gradle : Wrapper included - no local install needed
Spring Boot : 4.0.x (optional - core engine has no Spring dependency)