Skip to content

Commit

Permalink
Merge pull request quarkusio#38929 from mkouba/component-test-paramet…
Browse files Browse the repository at this point in the history
…erized-methods

QuarkusComponentTest: support parameterized test methods
  • Loading branch information
mkouba authored Feb 21, 2024
2 parents 716d6e8 + b7a6b48 commit e01528c
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 5 deletions.
3 changes: 3 additions & 0 deletions docs/src/main/asciidoc/getting-started-testing.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1666,11 +1666,14 @@ The fields annotated with `@Inject` and `@InjectMock` are injected after a test
Finally, the CDI request context is activated and terminated per each test method.

=== Injection

Test class fields annotated with `@jakarta.inject.Inject` and `@io.quarkus.test.InjectMock` are injected after a test instance is created.
Dependent beans injected into these fields are correctly destroyed before a test instance is destroyed.
Parameters of a test method for which a matching bean exists are resolved unless annotated with `@io.quarkus.test.component.SkipInject`.
Dependent beans injected into the test method arguments are correctly destroyed after the test method completes.

NOTE: Arguments of a `@ParameterizedTest` method that are provided by an `ArgumentsProvider`, for example with `@org.junit.jupiter.params.provider.ValueArgumentsProvider`, must be annotated with `@SkipInject`.

=== Auto Mocking Unsatisfied Dependencies

Unlike in regular CDI environments the test does not fail if a component injects an unsatisfied dependency.
Expand Down
5 changes: 5 additions & 0 deletions test-framework/junit5-component/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@
<artifactId>jakarta.ws.rs-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import jakarta.inject.Provider;

import org.jboss.logging.Logger;
import org.junit.jupiter.api.Test;

import io.quarkus.arc.InjectableInstance;
import io.quarkus.arc.processor.AnnotationsTransformer;
Expand Down Expand Up @@ -98,7 +97,7 @@ QuarkusComponentTestConfiguration update(Class<?> testClass) {
// - not annotated with @InjectMock
// - not annotated with @SkipInject
for (Method method : current.getDeclaredMethods()) {
if (method.isAnnotationPresent(Test.class)) {
if (QuarkusComponentTestExtension.isTestMethod(method)) {
for (Parameter param : method.getParameters()) {
if (QuarkusComponentTestExtension.BUILTIN_PARAMETER.test(param)
|| param.isAnnotationPresent(InjectMock.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
Expand Down Expand Up @@ -63,6 +64,7 @@
import org.jboss.jandex.Type;
import org.jboss.jandex.Type.Kind;
import org.jboss.logging.Logger;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
Expand All @@ -79,6 +81,7 @@
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;

import io.quarkus.arc.All;
import io.quarkus.arc.Arc;
Expand Down Expand Up @@ -269,7 +272,7 @@ public boolean supportsParameter(ParameterContext parameterContext, ExtensionCon
// Target is empty for constructor or static method
parameterContext.getTarget().isPresent()
// Only test methods are supported
&& parameterContext.getDeclaringExecutable().isAnnotationPresent(Test.class)
&& isTestMethod(parameterContext.getDeclaringExecutable())
// A method/param annotated with @SkipInject is never supported
&& !parameterContext.isAnnotated(SkipInject.class)
&& !parameterContext.getDeclaringExecutable().isAnnotationPresent(SkipInject.class)
Expand Down Expand Up @@ -999,7 +1002,7 @@ private List<Field> findInjectFields(Class<?> testClass) {
}

private List<Parameter> findInjectParams(Class<?> testClass) {
List<Method> testMethods = findMethods(testClass, m -> m.isAnnotationPresent(Test.class));
List<Method> testMethods = findMethods(testClass, QuarkusComponentTestExtension::isTestMethod);
List<Parameter> ret = new ArrayList<>();
for (Method method : testMethods) {
for (Parameter param : method.getParameters()) {
Expand All @@ -1015,7 +1018,7 @@ private List<Parameter> findInjectParams(Class<?> testClass) {
}

private List<Parameter> findInjectMockParams(Class<?> testClass) {
List<Method> testMethods = findMethods(testClass, m -> m.isAnnotationPresent(Test.class));
List<Method> testMethods = findMethods(testClass, QuarkusComponentTestExtension::isTestMethod);
List<Parameter> ret = new ArrayList<>();
for (Method method : testMethods) {
for (Parameter param : method.getParameters()) {
Expand All @@ -1028,6 +1031,12 @@ private List<Parameter> findInjectMockParams(Class<?> testClass) {
return ret;
}

static boolean isTestMethod(Executable method) {
return method.isAnnotationPresent(Test.class)
|| method.isAnnotationPresent(ParameterizedTest.class)
|| method.isAnnotationPresent(RepeatedTest.class);
}

private List<Field> findFields(Class<?> testClass, List<Class<? extends Annotation>> annotations) {
List<Field> fields = new ArrayList<>();
Class<?> current = testClass;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.quarkus.test.component.paraminject;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.concurrent.atomic.AtomicInteger;

import jakarta.annotation.PreDestroy;
import jakarta.enterprise.context.Dependent;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import io.quarkus.test.component.QuarkusComponentTest;
import io.quarkus.test.component.SkipInject;

@QuarkusComponentTest
public class ParameterInjectionParameterizedTest {

@ParameterizedTest
@ValueSource(strings = { "alpha", "bravo", "delta" })
public void testParamsInjection(@SkipInject String param, Converter converter) {
Assertions.assertThat(converter.convert(param)).isIn("ALPHA", "BRAVO", "DELTA");
}

@AfterAll
public static void afterAll() {
assertEquals(3, Converter.DESTROYED.get());
}

@Dependent
public static class Converter {

static final AtomicInteger DESTROYED = new AtomicInteger();

String convert(String param) {
return param.toUpperCase();
}

@PreDestroy
void destroy() {
DESTROYED.incrementAndGet();
}
}

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

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.concurrent.atomic.AtomicInteger;

import jakarta.annotation.PreDestroy;
import jakarta.enterprise.context.Dependent;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;

import io.quarkus.test.component.QuarkusComponentTest;

@QuarkusComponentTest
public class ParameterInjectionRepeatedTest {
@RepeatedTest(10)
public void testParamsInjection(
// component under test
Converter converter,
// ignored automatically, no need for `@SkipInject`
RepetitionInfo info) {
assertEquals(10, info.getTotalRepetitions());
assertEquals("FOOBAR", converter.convert("fooBar"));
}

@AfterAll
public static void afterAll() {
assertEquals(10, Converter.DESTROYED.get());
}

@Dependent
public static class Converter {
static final AtomicInteger DESTROYED = new AtomicInteger();

String convert(String param) {
return param.toUpperCase();
}

@PreDestroy
void destroy() {
DESTROYED.incrementAndGet();
}
}
}

0 comments on commit e01528c

Please sign in to comment.