-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Support composition of multiple parameterResolvers #1604
Comments
IIUC, the linked Looking closer at the linked PR it seems to me that of the two implementations only one will ever match as long as it's not a So, if there was a way for an extension to register other extensions, the For example, we could add an Do you think that would be useful? |
I think the issue is that there is no link between the I would rather not create multiple extensions, but instead have a method that allows me to iterate through multiple possibilities with their corresponding resolution strategy. |
Our intention was to make it possible to resolve all kinds of values, including You could create the missing link using public class MultiSourceParameterResolver implements ParameterResolver {
public static final String KEY = "resolvedParameter";
@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
Optional<Object> resolvedParameter = resolve(parameterContext);
resolvedParameter.ifPresent(value -> getStore(extensionContext, parameterContext).put(KEY, value));
return resolvedParameter.isPresent();
}
private Optional<Object> resolve(ParameterContext parameterContext) {
// just some dummy checks ;-)
if (parameterContext.isAnnotated(Deprecated.class)) {
return Optional.of("deprecated");
}
if (Integer.class.equals(parameterContext.getParameter().getType())) {
return Optional.of(42);
}
return Optional.empty();
}
@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
return getStore(extensionContext, parameterContext).get(KEY);
}
private Store getStore(ExtensionContext extensionContext, ParameterContext parameterContext) {
return extensionContext.getStore(Namespace.create(MultiSourceParameterResolver.class, parameterContext));
}
} |
While technically possible, I am not really a fan of that solution. If you would then add both After writing the above paragraph, I checked out the internal JUnit implementation, which takes care of any clashes. However, that handles clashes between extensions, but not any potential clashes within a single extension. In the above snippet, you are using the context to store the interim state. However, to me that feels very similar to doing the following: public class MultiSourceParameterResolver implements ParameterResolver {
private Object parameterValue;
@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
Optional<Object> resolvedParameter = resolve(parameterContext);
resolvedParameter.ifPresent(value -> this.parameterValue = value);
return resolvedParameter.isPresent();
}
private Optional<Object> resolve(ParameterContext parameterContext) {
// just some dummy checks ;-)
if (parameterContext.isAnnotated(Deprecated.class)) {
return Optional.of("deprecated");
}
if (Integer.class.equals(parameterContext.getParameter().getType())) {
return Optional.of(42);
}
return Optional.empty();
}
@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
return this.parameterValue;
}
} (Instead of storing the value in a However, I don't think that All in all, I realize this is mostly about "feels" rather than concrete evidence. I also realize we can just use the |
Well, storing it in an instance variable is error-prone when tests are executed in parallel. Thus, we always recommend storing state in I agree that resolution should happen in Let's keep this issue open for the time being and see if someone comes up with a more convincing proposal. |
@marcphilipp I voting up for something like that, but probably separated trait will make a bit more sense. |
+1, I want to impl a parameter resolver which only handles the parameter if it is not handled by another parameter resolver and it is quite hard ATM without doing a lot of reflection and depending on the engine to get the ExtensionRegistry |
Would also love to see this. My scenario: I use the I know wanted to add another I'll get in reach with the maintainer, because I think the feature will be useful for many others, but I wanted to leave a note here, that there the current state limits the great flexibility of JUnit Jupiter - of course, I'm sure you have reasons to do so at the moment. |
A trick to implement it is to integrate with main engine this way: https://github.com/apache/karaf-winegrower/blob/master/winegrower-extension/winegrower-testing/winegrower-testing-junit5/src/main/java/org/apache/winegrower/extension/testing/junit5/internal/engine/CaptureExtensionRegistry.java. Then you can test if another resolve supports it (https://github.com/apache/karaf-winegrower/blob/master/winegrower-extension/winegrower-testing/winegrower-testing-junit5/src/main/java/org/apache/winegrower/extension/testing/junit5/internal/BaseInjection.java#L40). It is way less elegant than priorities at engine level but works/unblock today. |
What about classic composition? If you have a
This, of course, presumes that you can change your annotation from If you can't change the
All in all, I like this idea, will see if we can implement it in an extension in JUnit Pioneer - and if it looks promising/good enough JUnit team can move it into core. |
@Michael1993 composition is almost immediately blocked by the fact you can't know all potential other extensions and integrate with all others - if it would be true then you would end up having all extensons un jupiter and then drop the extension concept. I think it is saner to have a kind of ranking per parameter (which could have a default value in ParameterResolver). This way extensions can evaluate their "priority" and jupiter can sort it to find the one to use. Note that it can also be dynamic if "getPriority" takes the same parameters than "supportsParamter", enabling the user to use a @priority or @MyExtensionOrder to select himself which one he wants without having to use a custom extension qualifier filtered in supports hook. |
Yeah, if you look at it from JUnit side, execution order is a big question mark. But my solution is on the client/user side - you control how you wrap the The second solution does have a problem with execution order but it's a last resort hack anyways. |
@Michael1993 hmm, your solution works if the user disables all extensions which are sometimes already composed so - to have tested it before the hack I shared before - it is very complex for end users to use when having multiple extensions - it is doable for simple cases, I agree. There is no issue except the dependency on the engine but I suspect it can be pushed in api module - with the priority option - it is controlled from both the extension and therefore user perspective where it works OOTB. |
This issue has been automatically marked as stale because it has not had recent activity. Given the limited bandwidth of the team, it will be automatically closed if no further activity occurs. Thank you for your contribution. |
This issue has been automatically closed due to inactivity. If you have a good use case for this feature, please feel free to reopen the issue. |
As part of mockito/mockito#3133 we will introduce a |
Overview
In Mockito, we want to support injection of multiple parameters. To that end, we have to check for a multitude of acceptable annotations and then later act on that annotation. This issue appeared when working on mockito/mockito#1503 which had to add a new annotation (
@Captor
) besides our@Mock
injection-capabilities.The author of the PR wrote a CompositeParameterResolver which would support this usecase. However, it feels like this kind of solution should live in JUnit, rather than being Mockito-specific. I would suspect that other projects will run into this problem (eventually).
Therefore, I would like to request a JUnit-official implementation for the use-case of composing various resolvers into a single parameter resolver, that then can be used in the extension.
Related Issues
ParameterResolver
s #1802Deliverables
resolveParameter
.The text was updated successfully, but these errors were encountered: