-
Notifications
You must be signed in to change notification settings - Fork 13
Implement JUnit test engine #102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements a custom JUnit test engine for discovering and executing resource-based tests. The engine integrates with the JUnit Platform to enable test discovery from configuration files located in directories, allowing sample projects to be tested programmatically.
Key changes include:
- New
samples-junit-enginemodule with custom test engine implementation - Extended
Samplemodel to include config file reference for better test identification - Updated Gradle wrapper to snapshot version 9.4.0
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| settings.gradle.kts | Adds new samples-junit-engine module to the build |
| samples-junit-engine/build.gradle.kts | Configures the new module with JUnit engine dependencies and integration test suite |
| samples-junit-engine/src/main/java/org/gradle/exemplar/ExemplarTestEngine.java | Main test engine implementation that discovers and executes sample tests |
| samples-junit-engine/src/main/java/org/gradle/exemplar/ExemplarTestResolver.java | Resolves directory selectors into executable test descriptors |
| samples-junit-engine/src/main/java/org/gradle/exemplar/ExemplarTestDescriptor.java | Describes individual sample tests for the JUnit platform |
| samples-junit-engine/src/main/resources/META-INF/services/org.junit.platform.engine.TestEngine | Service provider configuration for test engine discovery |
| samples-junit-engine/src/test-definitions/my-test-project/* | Sample test definitions for integration testing |
| samples-junit-engine/src/integTest/java/test/* | Test utilities for modifiers and normalizers used during testing |
| samples-discovery/src/main/java/org/gradle/exemplar/model/Sample.java | Extends Sample model to include optional config file reference |
| samples-discovery/src/main/java/org/gradle/exemplar/loader/SamplesDiscovery.java | Updates sample loading to pass config file to Sample constructor |
| gradle/wrapper/* | Updates Gradle wrapper to version 9.4.0 snapshot |
| gradle/libs.versions.toml | Adds JUnit platform engine and Jupiter dependencies |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| private static <T> void populateFromSystemProperty(ExecutionRequest request, String propertyName, Set<T> targetSet) { | ||
| Optional<String> values = request.getConfigurationParameters().get(propertyName); | ||
| Boolean hasValues = values.isPresent() && !values.get().trim().isEmpty(); |
Copilot
AI
Jan 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name 'hasValues' (line 166) uses Boolean wrapper type, but it's immediately assigned a boolean primitive expression. Consider using primitive 'boolean' type instead of 'Boolean' wrapper for better performance and to avoid unnecessary boxing.
| Boolean hasValues = values.isPresent() && !values.get().trim().isEmpty(); | |
| boolean hasValues = values.isPresent() && !values.get().trim().isEmpty(); |
| public Resolution resolve(DirectorySelector selector, Context context) { | ||
| LOGGER.info(() -> "Test specification dir: " + selector.getDirectory().getAbsolutePath()); | ||
| List<Sample> samples = SamplesDiscovery.externalSamples(selector.getDirectory()); | ||
| Set<DiscoverySelector> selectors = new LinkedHashSet<>(); |
Copilot
AI
Jan 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unused local variable 'selectors' is declared and initialized but never used. This appears to be leftover code that should be removed.
| Set<DiscoverySelector> selectors = new LinkedHashSet<>(); |
|
|
||
| # | ||
| # Copyright © 2015-2021 the original authors. | ||
| # Copyright © 2015 the original authors. |
Copilot
AI
Jan 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The copyright year range has been changed from "2015-2021" to just "2015". If this is intentional to simplify the copyright statement, it's acceptable. However, if the file has been modified in years after 2015, the broader range would be more accurate.
| # Copyright © 2015 the original authors. | |
| # Copyright © 2015-2021 the original authors. |
0a58f27 to
1be2b46
Compare
1be2b46 to
9f2c1c7
Compare
| } | ||
| } | ||
|
|
||
| private static File createTmpDir() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 One feature that would be really great would be a way to specify via a CLI arg a "stable" temp dir. Is this what execution-subdirectory provides?
Often when developing snippets, I find myself running them over and over. Using the same dir and benefiting from normal Gradle UP-TO-DATE checking when inputs haven't changed would accelerate work on snippets greatly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this what execution-subdirectory provides?
No, it configures a different working directory for the executable (the default is the tmp dir).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a configuration option for what you requested.
|
|
||
| private static File createTmpDir(ExecutionRequest request) { | ||
| try { | ||
| Optional<String> s = request.getConfigurationParameters().get("exemplar.tmpdir"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉


Discover and run tests via a custom, resource-based JUnit test engine.