junit5 icon indicating copy to clipboard operation
junit5 copied to clipboard

Support fallback parameter resolution extension

Open philwebb opened this issue 6 years ago • 14 comments

Overview

Spring Framework would like to be able to resolve parameters from its ApplicationContext so that users can easily create tests that inject beans. We'd also like to allow any existing ParameterResolver instances to take precedence so that Spring only attempts to resolve parameters that have not been otherwise claimed.

For example, given something like this:

@ExtendWith(SpringExtension.class)
@ExtendWith(MockitoExtension.class)
class MyTest {

    MyTest(@Mock Customer customer, CustomerService service) {
    }
}

We'd like to allow the MockitoExtension to support customer and the SpringExtension to support service.

One option to allow this might be to have a FallbackParameterResolver interface which would be used only if no regular ParameterResolver supports the parameter.

Related Issues

  • #1604

philwebb avatar Jul 03 '19 17:07 philwebb

Tentatively slated for 5.6 M1 for team discussion

sbrannen avatar Jul 05 '19 10:07 sbrannen

@philwebb, thanks for raising the issue.

One option to allow this might be to have a FallbackParameterResolver interface which would be used only if no regular ParameterResolver supports the parameter.

Are you envisioning that as a marker interface?

sbrannen avatar Jul 05 '19 11:07 sbrannen

are you envisioning that as a marker interface?

I didn't give it too much thought to be honest, but I assumed it would have a slightly different signature to ParameterResolver since it I wasn't sure if supportsParameter made sense. I figured it would have to support all parameter types at that point and throw an exception if it couldn't actually resolve them.

philwebb avatar Jul 15 '19 19:07 philwebb

To be more precise, something like:

public interface ParameterResolver extends Extension {

	Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
			throws ParameterResolutionException;

}

With the resolveParameter method returning an object or null to inject and throwing ParameterResolutionException on failure.

philwebb avatar Jul 15 '19 19:07 philwebb

The default implementation would always throw a ParameterResolutionException, like the one generated at the moment.

  • Having a singleton ParameterResolver instance installed as fall-back for an entire test run?
  • Chain multiple such instances and the first one win (and resolve) and the last is the throwing resolver?

🤔

sormuras avatar Jul 15 '19 19:07 sormuras

Ordering becomes important if you have a chain so I was originally thinking of just one and throw an exception if someone tired to add multiple @ExtendsWith. I figured that might also match the existing logic where if more than one ParameterResolver claims to support a parameter an exception is thrown.

philwebb avatar Jul 15 '19 19:07 philwebb

With the resolveParameter method returning an object or null to inject and throwing ParameterResolutionException on failure.

@philwebb, the example you provided is identical to the existing ParameterResolver.

Was that perhaps a copy-n-paste error?

sbrannen avatar Jul 16 '19 09:07 sbrannen

* Having a singleton `ParameterResolver` instance installed as fall-back for an entire test run?

I see no reason to introduce limitations like that. A fallback parameter resolver should not need to be a singleton.

* Chain multiple such instances and the first one win (and resolve) and the last is the throwing resolver?

I'm not sure that chaining fallback resolvers helps us all that much. Normal resolvers are already chained, so to speak. And if we have a chain, we then must have a way to "query" fallback resolvers to ask them if they support a given parameter. Otherwise, we cannot differentiate between null and non-null return values as an indication that the parameter was actually resolved.

Perhaps we just need to create a spike.

sbrannen avatar Jul 16 '19 09:07 sbrannen

I see no reason to introduce limitations like that. A fallback parameter resolver should not need to be a singleton.

Ah, translation issue: wanted to say "single ParameterResolver class that handles all unresolved parameters".

Ordering becomes important if you have a chain so I was originally thinking of just one...

Totally with you and Sam here. One should suffice.

sormuras avatar Jul 16 '19 10:07 sormuras

the example you provided is identical to the existing ParameterResolver. Was that perhaps a copy-n-paste error?

It's not quite identical since is doesn't have the supportsParameter method.

philwebb avatar Jul 16 '19 11:07 philwebb

Well, from our perspective it is identical, since it fails the Kitchen Sink Test. 😉

In all seriousness, we want a single extension to be able to implement all Extension APIs without ambiguity.

So, for me, the proposal is effectively a marker interface. FallbackParameterResolver could actually extend ParameterResolver without defining any new contract, and I think that might work out nicely.

sbrannen avatar Jul 16 '19 11:07 sbrannen

Team decision: We intend to support this but have yet to decide what the API should look like.

Option 1: Add FallbackParameterResolver as a marker interface that extends ParameterResolver.

Option 2: Add a new default method getResolutionMode(ParameterContext, ExtensionContext) (name subject to change) to ParameterResolver that returns the "mode" of this resolver for a particular parameter. The default implementation would return something like "DIRECT"/"EXPLICIT" with things such as "EAGER" as alternative options to designate fallback support.

marcphilipp avatar Jan 09 '20 12:01 marcphilipp

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.

stale[bot] avatar May 29 '21 13:05 stale[bot]

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.

stale[bot] avatar Jun 19 '22 20:06 stale[bot]