Repository: avaje/avaje-inject
Pull request #379 (2023-07-22 14:13:00)

InjectTest profiles
Now can set wiring profile with @InjectTest

sonatype-lift[bot]: ## Sonatype Lift is retiring
Sonatype Lift will be retiring on <b>Sep 12, 2023</b>, with its analysis stopping on Aug 12, 2023. We understand that this news may come as a disappointment, and Sonatype is committed to helping you transition off it seamlessly. If you’d like to retain your data, please export your issues from the web console.
We are extremely grateful and thank you for your support over the years.

<b>[📖 Read about the impacts and timeline](https://www.sonatype.com/lift-retirement)</b>

Patch:
diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java b/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java
index 5590d88c..37544848 100644
--- a/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java
+++ b/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java
@@ -34,14 +34,11 @@ final class ExternalProvider {
       return;
     }
 
-    final var iterator =
-        ServiceLoader.load(Module.class, ExternalProvider.class.getClassLoader()).iterator();
-
+    final var iterator = ServiceLoader.load(Module.class, ExternalProvider.class.getClassLoader()).iterator();
     if (!iterator.hasNext()) {
       System.out.println("No external modules detected");
       return;
     }
-
     while (iterator.hasNext()) {
       try {
         final var module = iterator.next();
@@ -70,9 +67,7 @@ final class ExternalProvider {
       return;
     }
     for (final Plugin plugin : ServiceLoader.load(Plugin.class, Processor.class.getClassLoader())) {
-
       System.out.println("Loaded Plugin: " + plugin.getClass().getCanonicalName());
-
       for (final Class<?> provide : plugin.provides()) {
         defaultScope.pluginProvided(provide.getCanonicalName());
       }
diff --git a/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java b/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java
index b7a21103..11ead28f 100644
--- a/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java
+++ b/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java
@@ -55,9 +55,7 @@ public class AvajeInjectPlugin implements Plugin<Project> {
     final Set<String> providedTypes = new HashSet<>();
 
     for (final var plugin : ServiceLoader.load(io.avaje.inject.spi.Plugin.class, cl)) {
-
       System.out.println("Loaded Plugin: " + plugin.getClass().getCanonicalName());
-
       for (final Class<?> provide : plugin.provides()) {
         providedTypes.add(provide.getCanonicalName());
       }
@@ -72,13 +70,10 @@ public class AvajeInjectPlugin implements Plugin<Project> {
     }
   }
 
-  private void writeProvidedModules(ClassLoader classLoader, FileWriter moduleWriter)
-      throws IOException {
+  private void writeProvidedModules(ClassLoader classLoader, FileWriter moduleWriter) throws IOException {
     final Set<String> providedTypes = new HashSet<>();
-    for (final io.avaje.inject.spi.Module module :
-        ServiceLoader.load(io.avaje.inject.spi.Module.class, classLoader)) {
+    for (final io.avaje.inject.spi.Module module : ServiceLoader.load(io.avaje.inject.spi.Module.class, classLoader)) {
       System.out.println("Detected External Module: " + module.getClass().getCanonicalName());
-
       for (final Class<?> provide : module.provides()) {
         providedTypes.add(provide.getCanonicalName());
       }
diff --git a/inject/src/main/java/io/avaje/inject/BeanScopeBuilder.java b/inject/src/main/java/io/avaje/inject/BeanScopeBuilder.java
index 1bb3967d..7b28ffd1 100644
--- a/inject/src/main/java/io/avaje/inject/BeanScopeBuilder.java
+++ b/inject/src/main/java/io/avaje/inject/BeanScopeBuilder.java
@@ -1,14 +1,14 @@
 package io.avaje.inject;
 
-import java.lang.reflect.Type;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-
 import io.avaje.inject.spi.Module;
 import io.avaje.inject.spi.PropertyRequiresPlugin;
 import io.avaje.lang.NonNullApi;
 import io.avaje.lang.Nullable;
 
+import java.lang.reflect.Type;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
 /**
  * Build a bean scope with options for shutdown hook and supplying external dependencies.
  * <p>
@@ -117,7 +117,7 @@ public interface BeanScopeBuilder {
    * }</pre>
    *
    * @param beans Externally provided beans used when injecting a dependency for the bean or the
-   *     interface(s) it implements
+   *              interface(s) it implements
    * @return This BeanScopeBuilder
    */
   BeanScopeBuilder beans(Object... beans);
diff --git a/inject/src/main/java/io/avaje/inject/Component.java b/inject/src/main/java/io/avaje/inject/Component.java
index d5f50c7c..2dfbc172 100644
--- a/inject/src/main/java/io/avaje/inject/Component.java
+++ b/inject/src/main/java/io/avaje/inject/Component.java
@@ -1,12 +1,12 @@
 package io.avaje.inject;
 
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
 /**
  * Identify a bean as component with singleton scope that avaje-inject will use.
  * <p>
@@ -67,7 +67,9 @@ public @interface Component {
   @Target({ElementType.TYPE, ElementType.PACKAGE})
   @interface Import {
 
-    /** Specify types to generate DI classes for. */
+    /**
+     * Specify types to generate DI classes for.
+     */
     Class<?>[] value();
   }
 }
diff --git a/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java b/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java
index e7edd415..c60c995a 100644
--- a/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java
+++ b/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java
@@ -1,8 +1,8 @@
 package io.avaje.inject;
 
 import io.avaje.applog.AppLog;
-import io.avaje.inject.spi.*;
 import io.avaje.inject.spi.Module;
+import io.avaje.inject.spi.*;
 import io.avaje.lang.NonNullApi;
 import io.avaje.lang.Nullable;
 import jakarta.inject.Provider;
@@ -12,7 +12,8 @@ import java.util.*;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
-import static java.lang.System.Logger.Level.*;
+import static java.lang.System.Logger.Level.DEBUG;
+import static java.lang.System.Logger.Level.INFO;
 
 /**
  * Build a bean scope with options for shutdown hook and supplying test doubles.
diff --git a/inject/src/main/java/io/avaje/inject/DConfigProps.java b/inject/src/main/java/io/avaje/inject/DConfigProps.java
index ee62897a..81124969 100644
--- a/inject/src/main/java/io/avaje/inject/DConfigProps.java
+++ b/inject/src/main/java/io/avaje/inject/DConfigProps.java
@@ -5,10 +5,7 @@ import io.avaje.inject.spi.PropertyRequiresPlugin;
 
 import java.util.Optional;
 
-
-/**
- * Avaje-Config based implementation of PropertyRequiresPlugin.
- */
+/** Avaje-Config based implementation of PropertyRequiresPlugin. */
 final class DConfigProps implements PropertyRequiresPlugin {
 
   @Override
@@ -25,4 +22,9 @@ final class DConfigProps implements PropertyRequiresPlugin {
   public boolean equalTo(String property, String value) {
     return value.equals(Config.getNullable(property));
   }
+
+  @Override
+  public void set(String property, String value) {
+    Config.setProperty(property, value);
+  }
 }
diff --git a/inject/src/main/java/io/avaje/inject/DSystemProps.java b/inject/src/main/java/io/avaje/inject/DSystemProps.java
index 8caba367..abde0c86 100644
--- a/inject/src/main/java/io/avaje/inject/DSystemProps.java
+++ b/inject/src/main/java/io/avaje/inject/DSystemProps.java
@@ -7,16 +7,21 @@ final class DSystemProps implements io.avaje.inject.spi.PropertyRequiresPlugin {
   @Override
   public Optional<String> get(String property) {
     return Optional.ofNullable(System.getProperty(property))
-        .or(() -> Optional.ofNullable(System.getenv(property)));
+      .or(() -> Optional.ofNullable(System.getenv(property)));
   }
 
   @Override
   public boolean contains(String property) {
     return System.getProperty(property) != null || System.getenv(property) != null;
   }
-  
+
   @Override
   public boolean equalTo(String property, String value) {
     return value.equals(System.getProperty(property)) || value.equals(System.getenv(property));
   }
+
+  @Override
+  public void set(String property, String value) {
+    System.setProperty(property, value);
+  }
 }
diff --git a/inject/src/main/java/io/avaje/inject/Profile.java b/inject/src/main/java/io/avaje/inject/Profile.java
index 84293feb..fa451896 100644
--- a/inject/src/main/java/io/avaje/inject/Profile.java
+++ b/inject/src/main/java/io/avaje/inject/Profile.java
@@ -1,11 +1,10 @@
 package io.avaje.inject;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
 
-import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 /**
  * Expresses a requirement for a bean to be wired/registered into the {@link BeanScope}.
diff --git a/inject/src/main/java/io/avaje/inject/QualifiedMap.java b/inject/src/main/java/io/avaje/inject/QualifiedMap.java
index 43548b51..002fa0a6 100644
--- a/inject/src/main/java/io/avaje/inject/QualifiedMap.java
+++ b/inject/src/main/java/io/avaje/inject/QualifiedMap.java
@@ -1,12 +1,12 @@
 package io.avaje.inject;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
 /**
  * Marks an <code>Map&lt;String, T&gt; </code> field/parameter to receive a map of beans keyed
  * by qualifier name.
@@ -17,7 +17,7 @@ import java.lang.annotation.Target;
  *   private final Map<String, Tasks> taskMap;
  *
  *   @Inject
- *   CrewMate(@QualifiedMap Map&lt;String, Tasks&gt taskMap) {
+ *   CrewMate(@QualifiedMap Map<String, Tasks> taskMap) {
  *     this.taskMap = taskMap;
  *   }
  *
@@ -26,4 +26,5 @@ import java.lang.annotation.Target;
  */
 @Target({PARAMETER, FIELD})
 @Retention(RUNTIME)
-public @interface QualifiedMap {}
+public @interface QualifiedMap {
+}
diff --git a/inject/src/main/java/io/avaje/inject/RequiresBean.java b/inject/src/main/java/io/avaje/inject/RequiresBean.java
index 55a63d13..0a28aa7a 100644
--- a/inject/src/main/java/io/avaje/inject/RequiresBean.java
+++ b/inject/src/main/java/io/avaje/inject/RequiresBean.java
@@ -1,11 +1,11 @@
 package io.avaje.inject;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
 
-import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 /**
  * Expresses a requirement for a bean to be wired/registered into the {@link BeanScope}.
@@ -58,7 +58,9 @@ public @interface RequiresBean {
   @Target({TYPE, METHOD, ANNOTATION_TYPE})
   @interface Container {
 
-    /** @return The required dependencies */
+    /**
+     * The required dependencies.
+     */
     RequiresBean[] value();
   }
 }
diff --git a/inject/src/main/java/io/avaje/inject/RequiresProperty.java b/inject/src/main/java/io/avaje/inject/RequiresProperty.java
index 41ac1378..f7bf7c50 100644
--- a/inject/src/main/java/io/avaje/inject/RequiresProperty.java
+++ b/inject/src/main/java/io/avaje/inject/RequiresProperty.java
@@ -1,11 +1,11 @@
 package io.avaje.inject;
 
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
 
-import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 /**
  * Expresses a requirement for a bean to be wired/registered into the {@link BeanScope}.
@@ -75,7 +75,9 @@ public @interface RequiresProperty {
   @Target({TYPE, METHOD, ANNOTATION_TYPE})
   @interface Container {
 
-    /** @return The required dependencies */
+    /**
+     * The required dependencies.
+     */
     RequiresProperty[] value();
   }
 }
diff --git a/inject/src/main/java/io/avaje/inject/aop/Aspect.java b/inject/src/main/java/io/avaje/inject/aop/Aspect.java
index e70a0f4e..a808966b 100644
--- a/inject/src/main/java/io/avaje/inject/aop/Aspect.java
+++ b/inject/src/main/java/io/avaje/inject/aop/Aspect.java
@@ -1,10 +1,6 @@
 package io.avaje.inject.aop;
 
-import java.lang.annotation.Annotation;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import java.lang.annotation.*;
 
 /**
  * Meta annotation used to define an Aspect.
@@ -36,7 +32,9 @@ public @interface Aspect {
    */
   int ordering() default 1000;
 
-  /** Marks an External Annotation as being used for aspects */
+  /**
+   * Marks an External Annotation as being used for aspects
+   */
   @Target({ElementType.PACKAGE, ElementType.TYPE})
   @Retention(RetentionPolicy.SOURCE)
   public @interface Import {
diff --git a/inject/src/main/java/io/avaje/inject/spi/Builder.java b/inject/src/main/java/io/avaje/inject/spi/Builder.java
index b760e514..da934702 100644
--- a/inject/src/main/java/io/avaje/inject/spi/Builder.java
+++ b/inject/src/main/java/io/avaje/inject/spi/Builder.java
@@ -250,10 +250,14 @@ public interface Builder {
    */
   boolean containsQualifier(String name);
 
-  /** Return true if the builder contains the given profile */
+  /**
+   * Return true if the builder contains the given profile
+   */
   boolean containsProfiles(List<String> type);
 
-  /** Return true if the builder contains all of the given profile */
+  /**
+   * Return true if the builder contains all of the given profile
+   */
   boolean containsAllProfiles(List<String> type);
 
   /**
diff --git a/inject/src/main/java/io/avaje/inject/spi/Module.java b/inject/src/main/java/io/avaje/inject/spi/Module.java
index ac45e70f..253aeddc 100644
--- a/inject/src/main/java/io/avaje/inject/spi/Module.java
+++ b/inject/src/main/java/io/avaje/inject/spi/Module.java
@@ -67,7 +67,6 @@ public interface Module {
   /**
    * These are the apects that this module requires whose implementations are provided by other external
    * modules (that are in the classpath at compile time).
-   *
    */
   default Class<?>[] autoRequiresAspects() {
     return EMPTY_CLASSES;
diff --git a/inject/src/main/java/io/avaje/inject/spi/Plugin.java b/inject/src/main/java/io/avaje/inject/spi/Plugin.java
index fd4cd166..9f89211f 100644
--- a/inject/src/main/java/io/avaje/inject/spi/Plugin.java
+++ b/inject/src/main/java/io/avaje/inject/spi/Plugin.java
@@ -12,18 +12,26 @@ import java.lang.reflect.Type;
  */
 public interface Plugin {
 
-  /** Empty array of classes. */
+  /**
+   * Empty array of classes.
+   */
   Class<?>[] EMPTY_CLASSES = {};
 
-  /** Apply the plugin to the scope builder. */
+  /**
+   * Apply the plugin to the scope builder.
+   */
   void apply(BeanScopeBuilder builder);
 
-  /** Return the classes that the plugin provides. */
+  /**
+   * Return the classes that the plugin provides.
+   */
   default Class<?>[] provides() {
     return EMPTY_CLASSES;
   }
 
-  /** Return the aspect classes that the plugin provides. */
+  /**
+   * Return the aspect classes that the plugin provides.
+   */
   default Class<?>[] providesAspects() {
     return EMPTY_CLASSES;
   }
diff --git a/inject/src/main/java/io/avaje/inject/spi/PropertyRequiresPlugin.java b/inject/src/main/java/io/avaje/inject/spi/PropertyRequiresPlugin.java
index a173210c..571d1834 100644
--- a/inject/src/main/java/io/avaje/inject/spi/PropertyRequiresPlugin.java
+++ b/inject/src/main/java/io/avaje/inject/spi/PropertyRequiresPlugin.java
@@ -2,36 +2,44 @@ package io.avaje.inject.spi;
 
 import java.util.Optional;
 
+import io.avaje.lang.NonNullApi;
+
 /**
- * Plugin interface which contains the application properties used for wiring. Used with {@link io.avaje.inject.RequiresProperty} and {@link io.avaje.inject.Profile}.
- * <p>
- * The plugin is loaded via ServiceLoader and defaults to an implementation
- * that uses {@link System#getProperty(String)} and {@link System#getenv(String)}.
+ * Plugin interface which contains the application properties used for wiring. Used with {@link
+ * io.avaje.inject.RequiresProperty} and {@link io.avaje.inject.Profile}.
+ *
+ * <p>The plugin is loaded via ServiceLoader and defaults to an implementation that uses {@link
+ * System#getProperty(String)} and {@link System#getenv(String)}.
  */
+@NonNullApi
 public interface PropertyRequiresPlugin {
 
-  /** Return a configuration value that might not exist. */
+  /**
+   * Return a configuration value that might not exist.
+   */
   Optional<String> get(String property);
 
-  /** Return true if the property is defined. */
-  boolean contains(String property);
-
   /**
-   * Return true if the property is not defined.
+   * Return true if the property is defined.
    */
+  boolean contains(String property);
+
+  /** Return true if the property is not defined. */
   default boolean missing(String property) {
     return !contains(property);
   }
 
-  /**
-   * Return true if the property is equal to the given value.
-   */
+  /** Return true if the property is equal to the given value. */
   boolean equalTo(String property, String value);
 
-  /**
-   * Return true if the property is not defined or not equal to the given value.
-   */
+  /** Return true if the property is not defined or not equal to the given value. */
   default boolean notEqualTo(String property, String value) {
     return !equalTo(property, value);
   }
+
+  /** Set a property for wiring. */
+  default void set(String property, String value) {
+
+    throw new UnsupportedOperationException("Not Implemented");
+  }
 }


Test patch:
diff --git a/blackbox-test-inject/src/main/java/org/example/myapp/ConfigPropertiesPlugin.java b/blackbox-test-inject/src/main/java/org/example/myapp/ConfigPropertiesPlugin.java
index 53f0120a..eb505913 100644
--- a/blackbox-test-inject/src/main/java/org/example/myapp/ConfigPropertiesPlugin.java
+++ b/blackbox-test-inject/src/main/java/org/example/myapp/ConfigPropertiesPlugin.java
@@ -31,4 +31,9 @@ public class ConfigPropertiesPlugin implements PropertyRequiresPlugin {
   public boolean notEqualTo(String property, String value) {
     return !value.equals(Config.getNullable(property));
   }
+
+  @Override
+  public void set(String property, String value) {
+    Config.setProperty(property, value);
+  }
 }
diff --git a/blackbox-test-inject/src/test/java/org/example/myapp/profile/ProfileTests.java b/blackbox-test-inject/src/test/java/org/example/myapp/profile/ProfileTests.java
index 9f939089..63ca562b 100644
--- a/blackbox-test-inject/src/test/java/org/example/myapp/profile/ProfileTests.java
+++ b/blackbox-test-inject/src/test/java/org/example/myapp/profile/ProfileTests.java
@@ -1,25 +1,25 @@
 package org.example.myapp.profile;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.IOException;
 
-import org.example.myapp.conditional.Bird;
-import org.example.myapp.conditional.Bird.BlueJay;
-import org.example.myapp.conditional.Bird.StrawberryFinch;
-import org.example.myapp.conditional.BirdFactory;
-import org.example.myapp.conditional.BirdWatcher;
-import org.example.myapp.conditional.QualifiedBirdWatcher;
 import org.example.myapp.profile.Fish.CardinalTetra;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import io.avaje.config.Config;
 import io.avaje.inject.BeanScope;
+import io.avaje.inject.test.InjectTest;
+import jakarta.inject.Inject;
 
+@InjectTest(profiles = {"Fish", "testRepeatable"})
 class ProfileTests {
 
+  @Inject FishFactory factory;
+
   @BeforeEach
   void clearConfig() {
 
@@ -28,6 +28,9 @@ class ProfileTests {
 
   @Test
   void basic() throws IOException {
+
+    assertNotNull(factory != null);
+
     // just wire everything with no test scope, mocks etc
     final BeanScope beanScope = BeanScope.builder().build();
     assertTrue(beanScope.getOptional(Fish.class).isEmpty());
diff --git a/inject-test/src/main/java/io/avaje/inject/test/InjectTest.java b/inject-test/src/main/java/io/avaje/inject/test/InjectTest.java
index e6fe0bae..374d06fb 100644
--- a/inject-test/src/main/java/io/avaje/inject/test/InjectTest.java
+++ b/inject-test/src/main/java/io/avaje/inject/test/InjectTest.java
@@ -17,5 +17,7 @@ import java.lang.annotation.Target;
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface InjectTest {
+
+  /** Wiring profiles to use */
   String[] profiles() default {};
 }
diff --git a/inject-test/src/main/java/io/avaje/inject/test/MetaInfo.java b/inject-test/src/main/java/io/avaje/inject/test/MetaInfo.java
index d28f1361..0e11f8fb 100644
--- a/inject-test/src/main/java/io/avaje/inject/test/MetaInfo.java
+++ b/inject-test/src/main/java/io/avaje/inject/test/MetaInfo.java
@@ -1,5 +1,7 @@
 package io.avaje.inject.test;
 
+import java.util.Optional;
+
 import io.avaje.inject.BeanScope;
 import io.avaje.inject.BeanScopeBuilder;
 
@@ -41,6 +43,18 @@ final class MetaInfo {
     if (parent != null) {
       builder.parent(parent, false);
     }
+
+    final var profiles =
+        Optional.ofNullable(testInstance)
+            .map(Object::getClass)
+            .map(c -> c.getAnnotation(InjectTest.class))
+            .map(InjectTest::profiles)
+            .map(p -> String.join(",", p))
+            .orElse("");
+
+    if (!profiles.isBlank()) {
+      builder.propertyPlugin().set("avaje.profiles", profiles);
+    }
     // register mocks and spies local to this test
     reader.build(builder, testInstance);