New junit parameter provider from static fields. (#6232)
This commit is contained in:
parent
709756d68d
commit
d9e5760ea7
|
@ -0,0 +1,92 @@
|
|||
package ca.uhn.test.junit;
|
||||
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.api.extension.ParameterContext;
|
||||
import org.junit.jupiter.api.extension.ParameterResolutionException;
|
||||
import org.junit.jupiter.api.extension.ParameterResolver;
|
||||
import org.junit.platform.commons.util.ExceptionUtils;
|
||||
import org.junit.platform.commons.util.ReflectionUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static org.junit.platform.commons.util.AnnotationUtils.findAnnotatedFields;
|
||||
import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible;
|
||||
|
||||
/**
|
||||
* Register any field annotated with @{@link JunitFieldProvider} as a parameter provider, matching parameters by type.
|
||||
* Can also be used directly via @RegisterExtension, using values passed to the constructor.
|
||||
*/
|
||||
public class JunitFieldParameterProviderExtension implements BeforeAllCallback, BeforeEachCallback, ParameterResolver {
|
||||
|
||||
Set<Object> myValues = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Junit constructor for @{@link org.junit.jupiter.api.extension.ExtendWith}
|
||||
*/
|
||||
public JunitFieldParameterProviderExtension() {}
|
||||
|
||||
/**
|
||||
* Used for explicit registration.
|
||||
* @param theValues the values to register as provided junit parameters.
|
||||
*/
|
||||
public JunitFieldParameterProviderExtension(Object ...theValues) {
|
||||
Collections.addAll(myValues, theValues);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do we have a value matching the parameter type?
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
|
||||
Class<?> paramType = parameterContext.getParameter().getType();
|
||||
return myValues.stream().anyMatch(v->paramType.isAssignableFrom(v.getClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first value matching the parameter type.
|
||||
*/
|
||||
@Override
|
||||
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
|
||||
Class<?> paramType = parameterContext.getParameter().getType();
|
||||
return myValues.stream().filter(v->paramType.isAssignableFrom(v.getClass())).findAny().orElseThrow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all statics annotated with @JunitFieldProvider.
|
||||
*/
|
||||
@Override
|
||||
public void beforeAll(ExtensionContext context) throws Exception {
|
||||
collectFields(null, context.getRequiredTestClass(), ReflectionUtils::isStatic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect any instance fields annotated with @JunitFieldProvider.
|
||||
*/
|
||||
@Override
|
||||
public void beforeEach(ExtensionContext context) {
|
||||
context.getRequiredTestInstances().getAllInstances() //
|
||||
.forEach(instance -> collectFields(instance, instance.getClass(), ReflectionUtils::isStatic));
|
||||
}
|
||||
|
||||
private void collectFields(Object testInstance, Class<?> testClass,
|
||||
Predicate<Field> predicate) {
|
||||
|
||||
findAnnotatedFields(testClass, JunitFieldProvider.class, predicate).forEach(field -> {
|
||||
try {
|
||||
makeAccessible(field);
|
||||
myValues.add(field.get(testInstance));
|
||||
}
|
||||
catch (Exception t) {
|
||||
ExceptionUtils.throwAsUncheckedException(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package ca.uhn.test.junit;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Field annotation to register a value for use in JUnit 5 parameter resolution.
|
||||
*/
|
||||
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@ExtendWith(JunitFieldParameterProviderExtension.class)
|
||||
public @interface JunitFieldProvider {
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Junit helpers
|
||||
*/
|
||||
package ca.uhn.test.junit;
|
|
@ -0,0 +1,46 @@
|
|||
package ca.uhn.test.junit;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class JunitFieldParameterProviderExtensionTest {
|
||||
/** Verify statics annotated with @{@link JunitFieldProvider} are available to static junit methods. */
|
||||
@Nested
|
||||
class AnnotationRegistration implements IParameterizedTestTemplate {
|
||||
@JunitFieldProvider
|
||||
static final CaseSupplyingFixture ourFixture = new CaseSupplyingFixture();
|
||||
}
|
||||
/** Verify explicit registration of the extension.*/
|
||||
@Nested
|
||||
class ExplicitRegistration implements IParameterizedTestTemplate {
|
||||
static final CaseSupplyingFixture ourFixture = new CaseSupplyingFixture();
|
||||
@RegisterExtension
|
||||
static final JunitFieldParameterProviderExtension ourExtension = new JunitFieldParameterProviderExtension(ourFixture);
|
||||
}
|
||||
|
||||
static class CaseSupplyingFixture {
|
||||
public List<Integer> getCases() {
|
||||
return List.of(1,2,3);
|
||||
}
|
||||
}
|
||||
interface IParameterizedTestTemplate {
|
||||
@ParameterizedTest
|
||||
// intellij complains when a static source requires params
|
||||
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||
@MethodSource("testCaseSource")
|
||||
default void testStaticFactoryBound(int theTestCase) {
|
||||
// given
|
||||
assertTrue(theTestCase > 0);
|
||||
}
|
||||
|
||||
static List<Integer> testCaseSource(CaseSupplyingFixture theFixture) {
|
||||
return theFixture.getCases();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue