-
Notifications
You must be signed in to change notification settings - Fork 471
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
Global spec/feature run ordering extension with several available run order variants #1631
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## master #1631 +/- ##
=============================================
+ Coverage 0 78.29% +78.29%
- Complexity 0 4083 +4083
=============================================
Files 0 433 +433
Lines 0 13162 +13162
Branches 0 1692 +1692
=============================================
+ Hits 0 10305 +10305
- Misses 0 2224 +2224
- Partials 0 633 +633
☔ View full report in Codecov by Sentry. |
@leonard84, @Vampire: I think, this is ready for review, now that I have also added automated tests. |
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.
Take a look at https://github.com/spockframework/spock-gr8conf-2019/tree/code/src/main/java/org/gr8conf/spock
If you introduce randomness, then you should also provide a way to recreate the same execution, otherwise debugging issues can become a PITA.
You'll also need to create a new Random
with the seed for each spec when randomizing the features, so that you can recreate the same behavior when just executing one test.
spock-core/src/main/java/org/spockframework/runtime/SpockEngineDiscoveryPostProcessor.java
Show resolved
Hide resolved
That is an interesting thought, which I tend to agree with. I would, however, like to keep this as low-profile as possible. WDYT, would it be OK to keep using the same static single My extension is global, not annotation-driven. Exposing the seed via Spock config would mean to add one or two more settings there. For now, I did not create a separate config class / namespace for run randomisation, but simply two separate values for the runner. Adding one or two seeds would pollute the runner namespace too much, I think. If you insist to expose that via Spock config, I would rather add a sub-namespace in the runner section. But I would really like to avoid that. |
I've been considering for a while to introduce something like https://junit-pioneer.org/ for Spock extensions. Where they can live and mature at their own pace and potentially be promoted to |
That does not answer my questions. But if you like to get feedback on that idea: It would scare me off. I dislike long-winded, tedious processes with lots of ceremony, and you know that. I spent two spare hours today in order to prepare the PR, then one more for the test. Just like most other contributors, I do not have much more time than that and would lose interest in this contribution quickly. That way, you lose a lot of traction for the project. I saved you time already. Why not collaborate instead? Why don't you help me perfect the extension the way you like it to be, so you feel comfortable merging the PR? Just commit on top of this PR. We would both save time, have less debates. You get the code you feel comfortable with as a maintainer, while still retaining my commits, giving me some credit and recognition for the contribution. That would be the smart way to motivate and guide contributors. |
That is exactly the reason why that project would be worth while. It would have way less hurdles for new extensions as those are as-is code not implying they will be supported indefinitely.
This somehow implies that I have much more time than you at my hands. Sorry, but if you only want to provide proof of concept PRs, which I'll have to finish them myself somehow, then this it not really helpful. If they require additional work I'll put them on my todo list until I have time to work on them and their importance is greater than the other things I need to do. I'm careful when adding new features as Spock is a mature project, users expect for their tests to continue working across updates. That is why going fast and breaking things is not the correct modus operandi. Adding a bare bones implementation without considering further use-cases will most likely lead to larger changes, leaving us with the decision to add code to keep the old implementation working with the new one, or to break things. I'd like to avoid that by spending more time upfront to do it right the first time. You even commented multiple times yesterday that you'd like to wait on my feedback before spending time on this PR yet didn't even wait 24h 😔. I could have pointed you to the existing extensions and saved you some time. |
I do agree with that. But with regard to execution order randomisation, I think it is a different story, and the extension ought to be part of Spock Core, because it is so basic. Comparing Spock to Jupiter, they have one such core extension, and I think we should have one, too (not because Jupiter has it, but because it makes sense that it exists there), albeit just for randomisation, not all the variations they have. Manual ordering really should be outside of Spock core, because it is too exotic. But an opinionated test framework like Spock which also promotes test (order) independency, should have order randomisation out of the box. We already have core extensions which arguably are less helpful or essential.
It implies, that for me Spock is a pet project, but a sideshow. For you, it is the main OSS project you work on. My equivalent is AspectJ. You spend more time here and have responsibility as a maintainer. For me the same is true there.
Well, I simply used the time slice I had at my disposal. Starting something and not finishing it, tends to make it start rotting, because momentum is lost. See Sarek. We lost momentum (and I lost motivation), because it was difficult to get you collaborating back then. So, at some point I focused on other things.
You already pointed to your Gr8Conf extension in the other thread. But I did not want to copy and paste that one, but create something small, generic and easily maintainable from scratch and the way I felt comfortable with. I still think that an extension should do one thing, one thing only and also do it well. IMO, this PR meets those criteria. The only thing missing is that we agree on a way to inject random seeds. |
@leonard84, @Vampire: Please note my new commits and the updated PR description. Some additional explanation for why I chose the run orderer approach in combination with the new global extension lifecycle method, giving extension developers access to all spec infos at once: Using comparators has drawbacks. It is difficult to write a transitively consistent comparator for random ordering. Of course, something like public int compare(Integer o1, Integer o2) {
return random.nextInt(3) - 1;
} would effectively randomise the order, but neither would it be consistent with Besides, a comparator would not generate order numbers either. In theory, we could do completely without Please try to be open-minded and do not condemn the approach before really inspecting it, weighing pros and cons. Update: (Thinking aloud) Actually, the initial implementation of the random order extension was less intrusive, did not need a lot of infrastructural changes and did not strive to create anything generic where it was not needed. I am strongly in doubt that anyone will use the alphabetical orderer and that providing the manual, annotation-based orderer provides more than marginal (if any) added value to good testing practice The real value still is in the random orderer. I keep thinking "YAGNI" and am wondering, if it was worth the effort to generalise the approach. WDYT? Moreover, now you have what you are often so skeptical about: extra code to maintain and users with questions to support. The initial approach was really more minimal and easier to maintain, focusing on the main user value. |
FYI, the force-push just now is the result of rebase on master. |
Thank you for the update, the new implementation goes in the right direction, the only thing I'm still not convinced about is the I understand if you don't want to implement those changes and I will do them when I get to it. |
Thanks for the feedback. Before following your advice, I would like to understand your reasoning better, because if I follow advice blindly, the outcome might be suboptimal one more time. So please, allow me a few follow-up questions and remarks:
We are talking about prior art here. I simply followed the pattern I found in
So what is the problem with that? Is it bad that multiple extensions can manipulate execution order? That sounds pretty flexible to me. I am envisioning user-defined extensions which can implement a custom ordering, hence the convenient
Maybe you did not notice the |
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.
by extracting logging code into base spec.
@leonard84, I would appreciate more timely feedback. It has been almost three months now, and I can barely remember the details of this PR. Sorry to say this again, but over the years it has not become any less tedious and disheartening, trying to make any contributions to this project. Please, busy as you might be, try not to make contributors beg for your attention every single time, and try not to make them waste more time explaining themselves than it took to actually make the change. I think, I addressed all your recent concerns in my comments back in May 2023. |
Relates to #1443.
This PR contains support for specification and feature run ordering, including
IGlobalExtension.initSpecs(Collection<SpecInfo>)
,SpecProcessor
with methodprocess(Collection<SpecInfo>)
,@Order(int)
annotation for annotation-based run ordering,While personally still believing in what I said before...
... in the meantime I have extended the PR to provide the more generic solution mentioned above.