EngineDiscoveryRequestResolver
API overly complicated?
#3546
Replies: 1 comment 6 replies
-
I had the same thoughts/problems when I looked using the What you think of as your simplest example is the most complicated usecase. To resolve a unique id, each of the segments has to be resolved in turn. And this has to be done working backwards. However building the test descriptor tree has to be done working forwards. For example suppose we have the uniqueId (paraphrased) OuterClass -> InnerClass -> Parameterized method -> 3rd value. Then we need to do
This could be simplified by working forwards only, but that would require that each resolver knows about its possible descendants. |
Beta Was this translation helpful? Give feedback.
-
I was recently creating a small test engine for a rather specific use case. I was using
EngineDiscoveryRequestResolver
, but I got the impression that the API is overly complicated for no apparent reason. I haven't identified any reason at least. Unfortunately, I am a bit late as the feature was recently promoted to stable, but I still wanted to provide my feedback. (I am not sure if this is actually the right platform for feedback, though.)Unnecessary redundancy and nesting into callbacks
Here is the simplest example I could think of on how to use the API.
If
Context
would instead provide the methodvoid addMatch(TestDescriptor)
andTestDescriptor getParent()
, we could rewrite such methods into the following.We could also use
context.getParent().addChild(testDescriptor)
instead of providing theaddMatch
method. However, I will extend the method later.Note that this method is not only shorter and easier to read, it is also less error-prone. The previous implementation above provides the test descriptor to
context.addToParent
and returns it as part of theResolution
. This redundancy can cause confusing errors when you miss either of these steps. Also note that my example is very simple and doesn't include any hierarchy. In practice, the callback withinaddToParent
would often become noticeably larger, which makes this API even more frustrating to use.Match.Type
There are other aspects of the API which feel overcomplicated to me. Let's consider the
Match
class. The purpose of this class seems to distinguish between exact matches and partial matches, and to optionally add achildSelectorsSupplier
. There are four factory methods which can be used to construct aMatch
. (The constructor is private.)The
EngineDiscoveryRequestResolver
callschildSelectorsSupplier
only if the match is exact. This is the only usage of this property. This means that the factory methods (1), (3), and (4) are effectively identical. The second parameter of (4) is always ignored. This also means thatMatch.Type
is effectively redundant.childSelectorsSupplier
The
childSelectorsSupplier
is called when a descriptor shall be expanded. A descriptor is expanded if and only if the user supplied a selector which points to the descriptor or to a parent of the descriptor. Specifically, a descriptor is not expanded if the selector was only resolved overContext.resolve
.Context.resolve
is usually used to resolve a parent node of another node which was selected by the user.We can now provide the same functionality by overloading the
addMatch
method I introduced above.However, there is another point I find a bit irritating. Why do I have to use selectors here to identify the children? When you try to resolve the children, I think it is usually quite natural to also create the descriptors of the children. In fact, in my case I couldn't think of a sensible implementation which wouldn't follow the following steps:
getUniquieId()
on the child nodeUniqueIdSelector
and trow away the descriptorUniqueIdSelector
back to JUnitUniqueIdSelector
back to me by callingSelectorResolver.resolve
Why couldn't I just provide the descriptor to JUnit in step one? For example, the API could instead look like this:
Beta Was this translation helpful? Give feedback.
All reactions