From 740174dfc571017cba3f0b6aa8643586e395e765 Mon Sep 17 00:00:00 2001 From: Sascha Bieberstein Date: Tue, 26 May 2026 21:13:16 +0200 Subject: [PATCH 1/3] Remove support for legacy jUnit 4 Spock Groovy tests All tests have been migrated to jUnit 5 Kotlin or Java --- README.md | 6 +- .../sirius/kernel/BaseSpecification.groovy | 34 --- src/test/java/sirius/kernel/Scenario.java | 58 ----- .../java/sirius/kernel/ScenarioSuite.java | 234 ------------------ src/test/java/sirius/kernel/Scenarios.java | 28 --- .../java/sirius/kernel/SiriusExtension.java | 2 - .../kotlin/sirius/kernel/nls/FormatterTest.kt | 10 +- 7 files changed, 8 insertions(+), 364 deletions(-) delete mode 100644 src/test/java/sirius/kernel/BaseSpecification.groovy delete mode 100644 src/test/java/sirius/kernel/Scenario.java delete mode 100644 src/test/java/sirius/kernel/ScenarioSuite.java delete mode 100644 src/test/java/sirius/kernel/Scenarios.java diff --git a/README.md b/README.md index 9d92cd033..ab2fbf572 100644 --- a/README.md +++ b/README.md @@ -103,9 +103,9 @@ a single test (method) - the tests have to function independently of their surro has to either succeed in all three scenarios or it must fail each time. Everything else indicates an invalid test setup._ +Tests which require a running SIRIUS framework should use [`SiriusExtension`](src/test/java/sirius/kernel/SiriusExtension.java). + For testing, we heavily rely on **Docker** (especially when external systems like databases are required). SIRIUS has a build-in helper to start and stop **docker-compose** setups. See [DockerHelper](src/main/java/sirius/kernel/DockerHelper.java) for a list of supported configuration -settings or refer the [test setup](https://github.com/scireum/sirius-db/tree/main/src/test/resources) -of [sirius-db](https://github.com/scireum/sirius-db) and its -[TestSuite](https://github.com/scireum/sirius-db/blob/main/src/test/java/TestSuite.java) as an elaborate example. +settings or refer the [test setup](https://github.com/scireum/sirius-db/tree/main/src/test/resources) of [sirius-db](https://github.com/scireum/sirius-db) as an elaborate example. diff --git a/src/test/java/sirius/kernel/BaseSpecification.groovy b/src/test/java/sirius/kernel/BaseSpecification.groovy deleted file mode 100644 index 937a742a9..000000000 --- a/src/test/java/sirius/kernel/BaseSpecification.groovy +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Made with all the love in the world - * by scireum in Remshalden, Germany - * - * Copyright by scireum GmbH - * http://www.scireum.de - info@scireum.de - */ - -package sirius.kernel - -import sirius.kernel.async.CallContext -import spock.lang.Specification - -/** - * Base class for all specs that require the Sirius framework to be setup. - */ -class BaseSpecification extends Specification { - - /* - * Executed before each class. Will ensure that Sirius is ready - */ - def setupSpec() { - TestHelper.setUp(getClass()) - } - - /* - * Will be executed once before every spec method - */ - def setup() { - CallContext.initialize() - } - - -} diff --git a/src/test/java/sirius/kernel/Scenario.java b/src/test/java/sirius/kernel/Scenario.java deleted file mode 100644 index 5e4c0a82b..000000000 --- a/src/test/java/sirius/kernel/Scenario.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Made with all the love in the world - * by scireum in Remshalden, Germany - * - * Copyright by scireum GmbH - * http://www.scireum.de - info@scireum.de - */ - -package sirius.kernel; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Describes an alternative execution scenario for all tests. - *

- * Applying this annotation to the main TestSuite which must be - * executed using {@link ScenarioSuite}, another test run is created. - *

- * This run will enhance the system configuration by the file given in - * {@link #file()}. Additionally the tests to be executed can be filtered - * using a regex in {@link #includes()} and {@link #excludes()}. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Repeatable(Scenarios.class) -public @interface Scenario { - - /** - * Contains the name of the configuration file to load. - *

- * All settings provided here will overwrite those in test.conf and - * also the system configuration. - * - * @return the scenario configuration - */ - String file(); - - /** - * Contains a regular expression which filters the tests (fully qualified class names) - * to be executed. - * - * @return the filter regex or an empty string to execute all classes - */ - String includes() default ""; - - /** - * Contains a regular expression which filters the tests (fully qualified class names) - * to be ignored and therefore not executed. - * - * @return the filter regex or an empty string to execute all classes - */ - String excludes() default ""; - -} diff --git a/src/test/java/sirius/kernel/ScenarioSuite.java b/src/test/java/sirius/kernel/ScenarioSuite.java deleted file mode 100644 index bdfb2c15a..000000000 --- a/src/test/java/sirius/kernel/ScenarioSuite.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Made with all the love in the world - * by scireum in Remshalden, Germany - * - * Copyright by scireum GmbH - * http://www.scireum.de - info@scireum.de - */ - -package sirius.kernel; - -import com.googlecode.junittoolbox.WildcardPatternSuite; -import org.junit.jupiter.api.Tag; -import org.junit.runner.Description; -import org.junit.runner.Runner; -import org.junit.runner.notification.Failure; -import org.junit.runner.notification.RunNotifier; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.RunnerBuilder; -import org.spockframework.runtime.RunContext; -import org.spockframework.runtime.SpecInfoBuilder; -import org.spockframework.runtime.Sputnik; -import org.spockframework.runtime.model.FeatureInfo; -import org.spockframework.runtime.model.SpecInfo; -import sirius.kernel.commons.Strings; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Provides a special test suite which executes all tests in all {@link Scenario scenarios}. - *

- * This approach can be used to execute the same tests in multiple environments (e.g. by - * provisioning different containers via {@link DockerHelper}). - *

- * As this is a subclass of {@link WildcardPatternSuite} an appropriate - * {@code @SuiteClasses} annotation must be present. - */ -public class ScenarioSuite extends WildcardPatternSuite { - - private static final Map scopeSettings = new HashMap<>(); - private final List scenarios; - - private static class ScenarioRunner extends Runner { - - public static final Description FRAMEWORK_SETUP = - Description.createTestDescription(Sirius.class, "Framework setup"); - public static final Description FRAMEWORK_TEARDOWN = - Description.createTestDescription(Sirius.class, "Framework teardown"); - private final String scenarioFile; - private final String includes; - private final String excludes; - private final List allTests; - - protected ScenarioRunner(String scenarioFile, String includes, String excludes, List allTests) { - this.scenarioFile = scenarioFile; - this.includes = includes; - this.excludes = excludes; - this.allTests = allTests; - } - - protected List getEffectiveTests() { - Stream stream = allTests.stream(); - - // Filter on includes / excludes defined by @Scenario - if (Strings.isFilled(includes)) { - Pattern filterPattern = Pattern.compile(includes); - stream = stream.filter(r -> filterPattern.matcher(r.getDescription().getClassName()).matches()); - } - if (Strings.isFilled(excludes)) { - Pattern filterPattern = Pattern.compile(excludes); - stream = stream.filter(r -> !filterPattern.matcher(r.getDescription().getClassName()).matches()); - } - - return stream.collect(Collectors.toList()); - } - - @Override - public Description getDescription() { - Description description = Description.createSuiteDescription(determineScenarioName()); - description.addChild(FRAMEWORK_SETUP); - getEffectiveTests().forEach(runner -> description.addChild(runner.getDescription())); - description.addChild(FRAMEWORK_TEARDOWN); - return description; - } - - @Nonnull - public String determineScenarioName() { - if (Strings.isEmpty(scenarioFile)) { - return "Main Scenario"; - } - - return "Scenario: " + scenarioFile.replace(".conf", ""); - } - - @Override - public void run(RunNotifier runNotifier) { - System.setProperty(Sirius.SIRIUS_TEST_SCENARIO_PROPERTY, scenarioFile == null ? "" : scenarioFile); - runNotifier.fireTestStarted(FRAMEWORK_SETUP); - try { - // In case of a configured scenario, ensure framework shutdown - if (scenarioFile != null) { - TestHelper.performTearDown(); - } - TestHelper.setUp(ScenarioSuite.class); - } catch (Exception exception) { - runNotifier.fireTestFailure(new Failure(FRAMEWORK_SETUP, exception)); - } finally { - runNotifier.fireTestFinished(FRAMEWORK_SETUP); - } - - try { - getEffectiveTests().forEach(runner -> run(runNotifier, runner)); - } finally { - runNotifier.fireTestStarted(FRAMEWORK_TEARDOWN); - try { - TestHelper.tearDown(ScenarioSuite.class); - } catch (Exception exception) { - runNotifier.fireTestFailure(new Failure(FRAMEWORK_TEARDOWN, exception)); - } finally { - runNotifier.fireTestFinished(FRAMEWORK_TEARDOWN); - } - } - } - - private void run(RunNotifier runNotifier, Runner runner) { - if (ignoreUnrollFeatures(runNotifier, runner)) { - return; - } - - // Ignore tests with nightly tags. - // CAVEAT: this only work when annotated on class level, like the former scope - // This interception breaks surefires test counting - Tag tag = runner.getDescription().getTestClass().getAnnotation(Tag.class); - if (tag != null && !isScopeEnabled(tag.value())) { - runNotifier.fireTestIgnored(runner.getDescription()); - return; - } - - runner.run(runNotifier); - } - - /** - * Warn if {@link spock.lang.Unroll} is used as it crushes the output of JUNIT in every sane IDE. - *

- * Checks if a given suite is run via Sputnik and therefore based on Spock. If so, we check - * if an Unroll annotation is present and abort the spec if so. - *

- * This is done as the output generated by Unroll completely screws the output as shown - * in the JUNIT views in any sane IDE. Also, Unroll provides no real benefit except than - * generating more output (which is pointless if it ends up anywhere in the UI). - * - * @param runNotifier the notifier used for reporting - * @param runner the runner to check - * @return true if an invalid spec was found, false otherwise - */ - private boolean ignoreUnrollFeatures(RunNotifier runNotifier, Runner runner) { - if (!(runner instanceof Sputnik)) { - return false; - } - - SpecInfo spec = (new SpecInfoBuilder(runner.getDescription().getTestClass())).build(); - RunContext.get().createExtensionRunner(spec).run(); - if (spec.getAllFeatures().stream().anyMatch(FeatureInfo::isReportIterations)) { - runNotifier.fireTestIgnored(runner.getDescription()); - runNotifier.fireTestFailure(new Failure(Description.TEST_MECHANISM, - new IllegalStateException( - "@Unroll not supported by ScenarioSuite: " - + runner.getDescription().getTestClass()))); - return true; - } - - return false; - } - } - - /** - * Creates a new suite. - *

- * Use {@literal @RunWith(ScenarioSuite)} for a test suite. - * - * @param klass the test suite to execute - * @param builder the builder used to build the suite - * @throws InitializationError in case of an error during initialization - */ - public ScenarioSuite(Class klass, RunnerBuilder builder) throws InitializationError { - super(klass, builder); - this.scenarios = Arrays.asList(klass.getAnnotationsByType(Scenario.class)); - } - - @Override - protected List getChildren() { - List tests = super.getChildren(); - List result = new ArrayList<>(); - result.add(new ScenarioRunner(null, null, null, tests)); - if (scenarios != null) { - scenarios.stream() - .map(scenario -> new ScenarioRunner(scenario.file(), - scenario.includes(), - scenario.excludes(), - tests)) - .forEach(result::add); - } - - return result; - } - - /** - * Determines if the given test scope is enabled. - *

- * This evaluates against a JUnit groups that must be active. We test this by checking for exclusion - * of the group. - * - * @param scope the scope to check - * @return true if the scope is enabled, false otherwise - */ - public static boolean isScopeEnabled(String scope) { - if (Strings.isEmpty(scope)) { - return true; - } - - return scopeSettings.computeIfAbsent(scope, ignored -> { - // NOTE: this is potentially dangerous, as it works on one potentiall input property and not the - // actual system activated groups, but should work until spock will be removed - return !System.getProperty("test.excluded.groups", "").contains(scope); - }); - } -} diff --git a/src/test/java/sirius/kernel/Scenarios.java b/src/test/java/sirius/kernel/Scenarios.java deleted file mode 100644 index a5fdf0107..000000000 --- a/src/test/java/sirius/kernel/Scenarios.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Made with all the love in the world - * by scireum in Remshalden, Germany - * - * Copyright by scireum GmbH - * http://www.scireum.de - info@scireum.de - */ - -package sirius.kernel; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Used to provide several {@link Scenario scenarios} for a test suite. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface Scenarios { - /** - * The scenarios to execute. - * - * @return the scenarios to execute - */ - Scenario[] value(); -} diff --git a/src/test/java/sirius/kernel/SiriusExtension.java b/src/test/java/sirius/kernel/SiriusExtension.java index c250e9a83..634608691 100644 --- a/src/test/java/sirius/kernel/SiriusExtension.java +++ b/src/test/java/sirius/kernel/SiriusExtension.java @@ -16,8 +16,6 @@ /** * JUnit 5 extension to support the Sirius framework lifecycle. Annotated test classes will be provisioned with * a running framework and a cleared {@link CallContext} before each test. - *

- * Note: This currently does not support {@link sirius.kernel.Scenario scenarios}. */ public class SiriusExtension implements BeforeAllCallback, BeforeEachCallback { diff --git a/src/test/kotlin/sirius/kernel/nls/FormatterTest.kt b/src/test/kotlin/sirius/kernel/nls/FormatterTest.kt index ebed00c73..d4caa154f 100644 --- a/src/test/kotlin/sirius/kernel/nls/FormatterTest.kt +++ b/src/test/kotlin/sirius/kernel/nls/FormatterTest.kt @@ -8,8 +8,8 @@ package sirius.kernel.nls -import org.junit.Assert.assertThrows import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith import sirius.kernel.SiriusExtension import sirius.kernel.commons.Context @@ -77,7 +77,7 @@ class FormatterTest { fun `format fails when using unknown parameter`() { val pattern = "Test \${foo}" - assertThrows(IllegalArgumentException::class.java) { + assertThrows { Formatter.create(pattern).smartFormat() } } @@ -86,7 +86,7 @@ class FormatterTest { fun `format fails for missing curly bracket`() { val pattern = "Test \${foo" - assertThrows(IllegalArgumentException::class.java) { + assertThrows { Formatter.create(pattern).smartFormat() } } @@ -95,7 +95,7 @@ class FormatterTest { fun `format fails for missing square bracket`() { val pattern = "Test [\${foo}" - assertThrows(IllegalArgumentException::class.java) { + assertThrows { Formatter.create(pattern).smartFormat() } } @@ -104,7 +104,7 @@ class FormatterTest { fun `smartFormat fails for additional square bracket`() { val pattern = "Test [\${foo}]]" - assertThrows(IllegalArgumentException::class.java) { + assertThrows { Formatter.create(pattern).smartFormat() } } From 0b1c27b2188d9c485f49939b2ed11d075bc8341d Mon Sep 17 00:00:00 2001 From: Sascha Bieberstein Date: Tue, 26 May 2026 21:16:45 +0200 Subject: [PATCH 2/3] Provide proper run configuration for tests This utilizes the test view of IntelliJ instead of just giving simple Maven output. --- .run/mvn clean test - without nightly.run.xml | 29 ------------------- .run/test.run.xml | 15 ++++++++++ 2 files changed, 15 insertions(+), 29 deletions(-) delete mode 100644 .run/mvn clean test - without nightly.run.xml create mode 100644 .run/test.run.xml diff --git a/.run/mvn clean test - without nightly.run.xml b/.run/mvn clean test - without nightly.run.xml deleted file mode 100644 index fc51b3a56..000000000 --- a/.run/mvn clean test - without nightly.run.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.run/test.run.xml b/.run/test.run.xml new file mode 100644 index 000000000..85238672c --- /dev/null +++ b/.run/test.run.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file From 439e358ba74484209c3af9e8e446365c577ec061 Mon Sep 17 00:00:00 2001 From: Sascha Bieberstein Date: Wed, 27 May 2026 13:44:09 +0200 Subject: [PATCH 3/3] Bump sirius-parent to latest version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 50580e08e..a2d44660d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.scireum sirius-parent - 14.3.3 + 15.0.0 sirius-kernel SIRIUS kernel