-
Notifications
You must be signed in to change notification settings - Fork 468
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
Ability to run specs in a particular order #1443
Comments
Any updates. If I get a hint where it should be implemented I'll do it :) |
I guess it is relatively simple. Now you should be able to use extensions to define the spec order. |
Thanks. That helps a lot. At least I know how to create proof of concept. After adding new field to
I should sort it by this new field: spock/spock-core/src/main/java/org/spockframework/runtime/SpockEngineDiscoveryPostProcessor.java Lines 12 to 18 in e97e2ed
The field could be set by extension in visitSpec(SpecInfo spec) (for example user can define "rank", or seed as annotation parameter).
|
@Vampire, it works nicely with these changes in Spock: --- a/spock-core/src/main/java/org/spockframework/runtime/model/SpecInfo.java (revision Staged)
+++ b/spock-core/src/main/java/org/spockframework/runtime/model/SpecInfo.java (date 1681293989411)
@@ -48,6 +48,8 @@
private ExecutionMode executionMode = null;
private ExecutionMode childExecutionMode = null;
+ private int executionOrder;
+
private String pkg;
private String filename;
private String narrative;
@@ -66,6 +68,14 @@
private final List<FeatureInfo> features = new ArrayList<>();
+ public int getExecutionOrder() {
+ return executionOrder;
+ }
+
+ public void setExecutionOrder(int executionOrder) {
+ this.executionOrder = executionOrder;
+ }
+
public String getPackage() {
return pkg;
}
--- a/spock-core/src/main/java/org/spockframework/runtime/SpockEngineDiscoveryPostProcessor.java (revision Staged)
+++ b/spock-core/src/main/java/org/spockframework/runtime/SpockEngineDiscoveryPostProcessor.java (date 1681299546435)
@@ -5,6 +5,8 @@
import org.junit.platform.engine.*;
+import static java.util.Comparator.comparingInt;
+
class SpockEngineDiscoveryPostProcessor {
private static final Object[] EMPTY_ARGS = new Object[0];
@@ -14,6 +16,9 @@
SpockEngineDescriptor processedEngineDescriptor = new SpockEngineDescriptor(uniqueId, runContext);
engineDescriptor.getChildren().stream()
.map(child -> processSpecNode(child, runContext))
+ .sorted(comparingInt((TestDescriptor child) ->
+ child instanceof SpecNode ? ((SpecNode) child).getNodeInfo().getExecutionOrder() : 0
+ ))
.forEach(processedEngineDescriptor::addChild);
return processedEngineDescriptor;
} A simple example for a global extension is: package de.scrum_master.testing.extension
import org.spockframework.runtime.extension.IGlobalExtension
import org.spockframework.runtime.model.SpecInfo
class RandomOrderExtension implements IGlobalExtension {
private static final Random RANDOM = new Random()
@Override
void visitSpec(SpecInfo spec) {
spec.executionOrder = RANDOM.nextInt()
}
} And then of course META-INF/services/org.spockframework.runtime.extension.IGlobalExtension:
@leonard84, is this worth a PR in your opinion? The little extension could either be included into the Spock manual as an example or, if you think we should publish it as a standard extension, as part of Spock proper. |
Your last codeblock is wrong @kriegaex. :-) If we make a built-in random order extension, maybe it should also randomize the features within a spec, or maybe have a Spock configuration file extension to configure whether to randomize only features, only specs, both, or none, probably with none as default. Another option could be an even more generic extensions - also configurable via the config file - that has more ordering options similar to the Jupiter extension. |
It is not wrong, because, like I said, the extension is a simple proof-of-concept example which only randomises the execution order of specs - no more, no less. I do agree, however, that if we think about adding this as a built-in extension and not just as an inline Spock manual snippet, we could and should make it more universal and more powerful. That would be easy enough to achieve. |
What I meant is
It should be |
Oh, of course. Somehow, the wrong snippet must have ended up in my Windows clipboard. In my sample project, it is correct. I fixed it above. |
Another quick & easy example for randomising both the order of specs and the features within them would be, adding just a single line: package de.scrum_master.testing.extension
import org.spockframework.runtime.extension.IGlobalExtension
import org.spockframework.runtime.model.SpecInfo
class RandomOrderExtension implements IGlobalExtension {
private static final Random RANDOM = new Random()
@Override
void visitSpec(SpecInfo spec) {
spec.executionOrder = RANDOM.nextInt()
spec.features.each { it.executionOrder = RANDOM.nextInt() }
}
} |
@kriegaex That's great! I think we would need 3 different options. For example let's have specs
Plus we need to print the seed and allow configuring it in order to reproduce test. |
Yes, easy enough, like I said. My latest version is basically your option 4 |
Thanks for taking the time to implement that feature! I believe there is also value in a 4th way of randomizing in addition to the 3 provided by @janisz: randomize both specs and features but, unlike 3, only run a specific spec fully and only then continue with the next. For example |
I don't think option 3 is possible. |
@boris-petrov, yes, what you are suggesting makes more sense than option 3. Actually, my example implements your option 4, not option 3. @janisz, I do not even think that option 3 makes any sense, because it would require us to run Edit: @Vampire's comment was posted while I wrote mine, so our comments' contents intersect. |
Note to myself: We also need to make sure that random or manual (e.g. via an annotation-driven extension) ordering vs. |
It will win, because global extensions are run first, annotation-driven extensions last. :-) |
That might be so, but either way, there should be automated tests for that. Please also note my comment update regarding manual ordering. Then we are talking about two annotation-driven extensions. |
Can be used by extensions. Relates to spockframework#1443.
Supports run order randomization for specifications, features or a combination of both. Relates to spockframework#1443.
Supports run order randomization for specifications, features or a combination of both. Relates to spockframework#1443.
New lifecycle method initSpecs(Collection<SpecInfo> specs) is called once, before visiting single specifications later on in `visitSpec`. It enables global extensions to view all specifications as an ensemble, e.g. for iterating over them and rearranging their execution order. Relates to spockframework#1443.
SpecProcessor is designed to generically process a Collection<SpecInfo>, which e.g. is available to global extensions using the recently introduced lifecycle method initSpecs(Collection<SpecInfo>). New abstract class SpecOrderer is meant to be extended by other orderers wishing to assign run orders to specs/features via - SpecInfo.setExecutionOrder, - FeatureInfo.setExecutionOrder. Relates to spockframework#1443.
Extending the initial implementation for run order randomisation, the former is not merely a special case of run ordering. We now have - DefaultSpecOrderer (basically a no-op) - RandomSpecOrderer, - AlphabeticalSpecOrderer, - AnnotatationBasedSpecOrderer with @order(int). Relates to spockframework#1443.
Can be used by extensions. Relates to spockframework#1443.
Supports run order randomization for specifications, features or a combination of both. Relates to spockframework#1443.
New lifecycle method initSpecs(Collection<SpecInfo> specs) is called once, before visiting single specifications later on in `visitSpec`. It enables global extensions to view all specifications as an ensemble, e.g. for iterating over them and rearranging their execution order. Relates to spockframework#1443.
SpecProcessor is designed to generically process a Collection<SpecInfo>, which e.g. is available to global extensions using the recently introduced lifecycle method initSpecs(Collection<SpecInfo>). New abstract class SpecOrderer is meant to be extended by other orderers wishing to assign run orders to specs/features via - SpecInfo.setExecutionOrder, - FeatureInfo.setExecutionOrder. Relates to spockframework#1443.
Extending the initial implementation for run order randomisation, the former is not merely a special case of run ordering. We now have - DefaultSpecOrderer (basically a no-op) - RandomSpecOrderer, - AlphabeticalSpecOrderer, - AnnotatationBasedSpecOrderer with @order(int). Relates to spockframework#1443.
Ascending sort order is the default, so instead of making 'descending' default to false, we make 'ascending' default to true, getting rid of the logical double negation of calling the default "not descending". Relates to spockframework#1443.
Use Collection<FeatureInfo> method parameter instead of Collection<SpecInfo>, streamlining method implementations by factoring out looping over SpecInfos into SpecOrderer.process. Relates to spockframework#1443.
Both SpecInfo and FeatureInfo had identical executionOrder bean properties, declared redundantly. Therefore, I pulled them up into the base class. Relates to spockframework#1443.
Can be used by extensions. Relates to spockframework#1443.
Supports run order randomization for specifications, features or a combination of both. Relates to spockframework#1443.
New lifecycle method initSpecs(Collection<SpecInfo> specs) is called once, before visiting single specifications later on in `visitSpec`. It enables global extensions to view all specifications as an ensemble, e.g. for iterating over them and rearranging their execution order. Relates to spockframework#1443.
SpecProcessor is designed to generically process a Collection<SpecInfo>, which e.g. is available to global extensions using the recently introduced lifecycle method initSpecs(Collection<SpecInfo>). New abstract class SpecOrderer is meant to be extended by other orderers wishing to assign run orders to specs/features via - SpecInfo.setExecutionOrder, - FeatureInfo.setExecutionOrder. Relates to spockframework#1443.
Extending the initial implementation for run order randomisation, the former is not merely a special case of run ordering. We now have - DefaultSpecOrderer (basically a no-op) - RandomSpecOrderer, - AlphabeticalSpecOrderer, - AnnotatationBasedSpecOrderer with @order(int). Relates to spockframework#1443.
Ascending sort order is the default, so instead of making 'descending' default to false, we make 'ascending' default to true, getting rid of the logical double negation of calling the default "not descending". Relates to spockframework#1443.
Use Collection<FeatureInfo> method parameter instead of Collection<SpecInfo>, streamlining method implementations by factoring out looping over SpecInfos into SpecOrderer.process. Relates to spockframework#1443.
Both SpecInfo and FeatureInfo had identical executionOrder bean properties, declared redundantly. Therefore, I pulled them up into the base class. Relates to spockframework#1443.
Is your feature request related to a problem?
I run all my other tests in randomized order - integration tests and frontend tests. I would like to run my backend-specific tests in randomized order as well. This would allow me to catch issues with dependencies between tests (which of course I don't want to be there). Just recently I spent a few hours debugging an issue in my tests that appeared only when different files were run in a specific order. I would like to protect myself from that.
Describe the solution you'd like
Something like Jupiter's
junit.jupiter.testclass.order.default = org.junit.jupiter.api.ClassOrderer$Random
.Describe alternatives you've considered
There is some more context about this issue in Gitter.
Additional context
No response
The text was updated successfully, but these errors were encountered: