Skip to content

Commit

Permalink
QuarkusComponentTest: refactorings and API changes
Browse files Browse the repository at this point in the history
- determine the test phase when the container is started from the
TestInstance#value()
- introduce the QuarkusComponentTestExtensionBuilder to create immutable
extension instance when programmatic API is used
- TestConfigProperty can be declared on test methods
  • Loading branch information
mkouba committed Sep 6, 2023
1 parent 3dbd75d commit fae399e
Show file tree
Hide file tree
Showing 19 changed files with 635 additions and 314 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,20 @@ public interface MockBeanConfigurator<T> {
* @param create
* @return the test extension
*/
QuarkusComponentTestExtension create(Function<SyntheticCreationalContext<T>, T> create);
QuarkusComponentTestExtensionBuilder create(Function<SyntheticCreationalContext<T>, T> create);

/**
* A Mockito mock object created from the bean class is used as a bean instance.
*
* @return the test extension
*/
QuarkusComponentTestExtension createMockitoMock();
QuarkusComponentTestExtensionBuilder createMockitoMock();

/**
* A Mockito mock object created from the bean class is used as a bean instance.
*
* @return the test extension
*/
QuarkusComponentTestExtension createMockitoMock(Consumer<T> mockInitializer);
QuarkusComponentTestExtensionBuilder createMockitoMock(Consumer<T> mockInitializer);

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

class MockBeanConfiguratorImpl<T> implements MockBeanConfigurator<T> {

final QuarkusComponentTestExtension test;
final QuarkusComponentTestExtensionBuilder builder;
final Class<?> beanClass;
Set<Type> types;
Set<Annotation> qualifiers;
Expand All @@ -44,8 +44,8 @@ class MockBeanConfiguratorImpl<T> implements MockBeanConfigurator<T> {
Set<org.jboss.jandex.Type> jandexTypes;
Set<AnnotationInstance> jandexQualifiers;

public MockBeanConfiguratorImpl(QuarkusComponentTestExtension test, Class<?> beanClass) {
this.test = test;
public MockBeanConfiguratorImpl(QuarkusComponentTestExtensionBuilder builder, Class<?> beanClass) {
this.builder = builder;
this.beanClass = beanClass;
this.types = new HierarchyDiscovery(beanClass).getTypeClosure();

Expand Down Expand Up @@ -142,19 +142,19 @@ public MockBeanConfigurator<T> defaultBean(boolean defaultBean) {
}

@Override
public QuarkusComponentTestExtension create(Function<SyntheticCreationalContext<T>, T> create) {
public QuarkusComponentTestExtensionBuilder create(Function<SyntheticCreationalContext<T>, T> create) {
this.create = create;
return register();
}

@Override
public QuarkusComponentTestExtension createMockitoMock() {
public QuarkusComponentTestExtensionBuilder createMockitoMock() {
this.create = c -> QuarkusComponentTestExtension.cast(Mockito.mock(beanClass));
return register();
}

@Override
public QuarkusComponentTestExtension createMockitoMock(Consumer<T> mockInitializer) {
public QuarkusComponentTestExtensionBuilder createMockitoMock(Consumer<T> mockInitializer) {
this.create = c -> {
T mock = QuarkusComponentTestExtension.cast(Mockito.mock(beanClass));
mockInitializer.accept(mock);
Expand All @@ -163,9 +163,9 @@ public QuarkusComponentTestExtension createMockitoMock(Consumer<T> mockInitializ
return register();
}

public QuarkusComponentTestExtension register() {
test.registerMockBean(this);
return test;
public QuarkusComponentTestExtensionBuilder register() {
builder.registerMockBean(this);
return builder;
}

boolean matches(BeanResolver beanResolver, org.jboss.jandex.Type requiredType, Set<AnnotationInstance> qualifiers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
* <p>
* For primitives the default values as defined in the JLS are used. For any other type {@code null} is injected.
*
* @see QuarkusComponentTestExtension#useDefaultConfigProperties()
* @see QuarkusComponentTestExtensionBuilder#useDefaultConfigProperties()
*/
boolean useDefaultConfigProperties() default false;

Expand All @@ -55,17 +55,17 @@
/**
* The ordinal of the config source used for all test config properties.
*
* @see QuarkusComponentTestExtension#setConfigSourceOrdinal(int)
* @see QuarkusComponentTestExtensionBuilder#setConfigSourceOrdinal(int)
*/
int configSourceOrdinal() default QuarkusComponentTestExtension.DEFAULT_CONFIG_SOURCE_ORDINAL;
int configSourceOrdinal() default QuarkusComponentTestExtensionBuilder.DEFAULT_CONFIG_SOURCE_ORDINAL;

/**
* The additional annotation transformers.
* <p>
* The initial set includes the {@link JaxrsSingletonTransformer}.
*
* @see AnnotationsTransformer
* @see QuarkusComponentTestExtension#addAnnotationsTransformer(AnnotationsTransformer)
* @see QuarkusComponentTestExtensionBuilder#addAnnotationsTransformer(AnnotationsTransformer)
*/
Class<? extends AnnotationsTransformer>[] annotationsTransformers() default {};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.quarkus.test.component;

import java.util.Map;
import java.util.Set;

import org.eclipse.microprofile.config.spi.ConfigSource;

class QuarkusComponentTestConfigSource implements ConfigSource {

private final Map<String, String> configProperties;
private final int ordinal;

QuarkusComponentTestConfigSource(Map<String, String> configProperties, int ordinal) {
this.configProperties = configProperties;
this.ordinal = ordinal;
}

@Override
public Set<String> getPropertyNames() {
return configProperties.keySet();
}

@Override
public String getValue(String propertyName) {
return configProperties.get(propertyName);
}

@Override
public String getName() {
return QuarkusComponentTestExtension.class.getName();
}

@Override
public int getOrdinal() {
return ordinal;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package io.quarkus.test.component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jakarta.enterprise.event.Event;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.inject.Inject;

import org.jboss.logging.Logger;

import io.quarkus.arc.processor.AnnotationsTransformer;

class QuarkusComponentTestConfiguration {

private static final Logger LOG = Logger.getLogger(QuarkusComponentTestConfiguration.class);

final Map<String, String> configProperties;
final List<Class<?>> componentClasses;
final List<MockBeanConfiguratorImpl<?>> mockConfigurators;
final boolean useDefaultConfigProperties;
final boolean addNestedClassesAsComponents;
final int configSourceOrdinal;
final List<AnnotationsTransformer> annotationsTransformers;

QuarkusComponentTestConfiguration(Map<String, String> configProperties, List<Class<?>> componentClasses,
List<MockBeanConfiguratorImpl<?>> mockConfigurators, boolean useDefaultConfigProperties,
boolean addNestedClassesAsComponents, int configSourceOrdinal,
List<AnnotationsTransformer> annotationsTransformers) {
this.configProperties = configProperties;
this.componentClasses = componentClasses;
this.mockConfigurators = mockConfigurators;
this.useDefaultConfigProperties = useDefaultConfigProperties;
this.addNestedClassesAsComponents = addNestedClassesAsComponents;
this.configSourceOrdinal = configSourceOrdinal;
this.annotationsTransformers = annotationsTransformers;
}

/**
*
* @param testClass
* @param testMethod
* @return a new configuration
*/
QuarkusComponentTestConfiguration update(Class<?> testClass, Method testMethod) {
Map<String, String> configProperties = new HashMap<>(this.configProperties);
List<Class<?>> componentClasses = new ArrayList<>(this.componentClasses);
boolean useDefaultConfigProperties = this.useDefaultConfigProperties;
boolean addNestedClassesAsComponents = this.addNestedClassesAsComponents;
int configSourceOrdinal = this.configSourceOrdinal;
List<AnnotationsTransformer> annotationsTransformers = new ArrayList<>(this.annotationsTransformers);

QuarkusComponentTest testAnnotation = testClass.getAnnotation(QuarkusComponentTest.class);
if (testAnnotation != null) {
Collections.addAll(componentClasses, testAnnotation.value());
useDefaultConfigProperties = testAnnotation.useDefaultConfigProperties();
addNestedClassesAsComponents = testAnnotation.addNestedClassesAsComponents();
configSourceOrdinal = testAnnotation.configSourceOrdinal();
Class<? extends AnnotationsTransformer>[] transformers = testAnnotation.annotationsTransformers();
if (transformers.length > 0) {
for (Class<? extends AnnotationsTransformer> transformerClass : transformers) {
try {
annotationsTransformers.add(transformerClass.getDeclaredConstructor().newInstance());
} catch (Exception e) {
LOG.errorf("Unable to instantiate %s", transformerClass);
}
}
}
}
// All fields annotated with @Inject represent component classes
Class<?> current = testClass;
while (current != null) {
for (Field field : current.getDeclaredFields()) {
if (field.isAnnotationPresent(Inject.class) && !resolvesToBuiltinBean(field.getType())) {
componentClasses.add(field.getType());
}
}
current = current.getSuperclass();
}
// All static nested classes declared on the test class are components
if (addNestedClassesAsComponents) {
for (Class<?> declaredClass : testClass.getDeclaredClasses()) {
if (Modifier.isStatic(declaredClass.getModifiers())) {
componentClasses.add(declaredClass);
}
}
}

List<TestConfigProperty> testConfigProperties = new ArrayList<>();
Collections.addAll(testConfigProperties, testClass.getAnnotationsByType(TestConfigProperty.class));
if (testMethod != null) {
Collections.addAll(testConfigProperties, testMethod.getAnnotationsByType(TestConfigProperty.class));
}
for (TestConfigProperty testConfigProperty : testConfigProperties) {
configProperties.put(testConfigProperty.key(), testConfigProperty.value());
}

return new QuarkusComponentTestConfiguration(Map.copyOf(configProperties), List.copyOf(componentClasses),
this.mockConfigurators,
useDefaultConfigProperties, addNestedClassesAsComponents, configSourceOrdinal,
List.copyOf(annotationsTransformers));
}

private boolean resolvesToBuiltinBean(Class<?> rawType) {
return Instance.class.isAssignableFrom(rawType) || Event.class.equals(rawType) || BeanManager.class.equals(rawType);
}

}
Loading

0 comments on commit fae399e

Please sign in to comment.