I apologize if this ends up being a question... if so could you please add an example to the reference documentation. Since constructor injection is a spring core feature and not a spring boot feature I think this is right place to raise this issue.

Problem

I'd like to inject an ArgumentsProvider's constructor, but it seems that the ArgumentsProvider does not have a parameter resolver registered; which is possible now.

import static org.assertj.core.api.Assertions.assertThat;

import com.myorg.dto.CreditCardAccount;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PerformanceTest {

  @ParameterizedTest
  @ArgumentsSource(Clients.class)
  void testClient(CommonCardAccountRepository repository) {
    var referenceId = "0";
    var cca = repository.getCreditCardAccount(referenceId);
    assertThat(cca)
      .isInstanceOf(CreditCardAccount.class)
      .hasFieldOrPropertyWithValue("accountReferenceId", referenceId);
  }

  static class Clients implements ArgumentsProvider {

    int port;

    @Autowired
    Clients(@LocalServerPort int port) {
      this.port = port;
    }

    @Override
    public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
      return Stream.of(Arguments.arguments(new CommonCardAccountRepositoryWebClientDefault(port)));
    }
  }
}

Constructor injecting into the base test is working.

Solution

Spring should fully register the paremeter resolver such that this works in the same way that it does on the constructor for the base test. I don't really know what that means though, or why it doesn't work now.

extended solution

Simply give me a base argument source that can inject the stream of arguments safely with @LocalServerPort

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PerformanceTest {

  @ParameterizedTest
  @ArgumentsSource(Clients.class)
  void testClient(CommonCardAccountRepository repository) {
    var referenceId = "0";
    var cca = repository.getCreditCardAccount(referenceId);
    assertThat(cca)
      .isInstanceOf(CreditCardAccount.class)
      .hasFieldOrPropertyWithValue("accountReferenceId", referenceId);
  }

// assumes that LocalServerPort is somehow injected into CommonCardAccountRepository
  static class Clients extends BeanCollectionArgumentsProvider<CommonCardAcountRepository> {}

I'm not certain if this use case is common enough to be worth pursuing, but may be worthy of it's own ticket.

Env

Spring Boot 3.3.7 Java 21

Comment From: sbrannen

I'd like to inject an ArgumentSource constructor but it seems that the ArgumentSource does not have a parameter resolver registered; which is possible now.

That feature was introduced in the recently released JUnit Jupiter 5.12:

  • https://github.com/junit-team/junit5/issues/4018

Which version of JUnit Jupiter are you using?