OutputCaptureExtension doesn't work in native image tests, as seen here.

It fails with:

  JUnit Jupiter:OutputCaptureTests
    ClassSource [className = 'com.example.commandlinerunner.OutputCaptureTests', filePosition = null]
    => java.lang.NoSuchMethodException: org.springframework.boot.test.system.OutputCapture.<init>()
       java.base@17.0.5/java.lang.Class.getConstructor0(DynamicHub.java:3585)
       java.base@17.0.5/java.lang.Class.getDeclaredConstructor(DynamicHub.java:2754)
       org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:527)
       org.junit.platform.commons.support.ReflectionSupport.newInstance(ReflectionSupport.java:181)
       org.junit.jupiter.api.extension.ExtensionContext$Store.lambda$getOrComputeIfAbsent$0(ExtensionContext.java:528)
       [...]
       Suppressed: java.lang.NoSuchMethodException: org.springframework.boot.test.system.OutputCapture.<init>()
         java.base@17.0.5/java.lang.Class.getConstructor0(DynamicHub.java:3585)
         java.base@17.0.5/java.lang.Class.getDeclaredConstructor(DynamicHub.java:2754)
         org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:527)
         org.junit.platform.commons.support.ReflectionSupport.newInstance(ReflectionSupport.java:181)
         org.junit.jupiter.api.extension.ExtensionContext$Store.lambda$getOrComputeIfAbsent$0(ExtensionContext.java:528)
         [...]
       Suppressed: java.lang.NoSuchMethodException: org.springframework.boot.test.system.OutputCapture.<init>()
         java.base@17.0.5/java.lang.Class.getConstructor0(DynamicHub.java:3585)
         java.base@17.0.5/java.lang.Class.getDeclaredConstructor(DynamicHub.java:2754)
         org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:527)
         org.junit.platform.commons.support.ReflectionSupport.newInstance(ReflectionSupport.java:181)
         org.junit.jupiter.api.extension.ExtensionContext$Store.lambda$getOrComputeIfAbsent$0(ExtensionContext.java:528)
         [...]

Comment From: mhalbritter

It runs with a config like this:

[
  {
    "condition": {
      "typeReachable": "org.springframework.boot.test.system.OutputCaptureExtension"
    },
    "name": "org.springframework.boot.test.system.OutputCapture",
    "methods": [
      {
        "name": "<init>",
        "parameterTypes": [
        ]
      }
    ]
  }
]

The thing is, this @ExtendWith(OutputCaptureExtension.class) can be used without any involvement of Spring (Boot) in JUnit 5 at all, so we can't hook a RuntimeHintsRegistrar in it. We can either write this config when running processTestAot or put it as a file in META-INF/native-image/org.springframework.boot/spring-boot-test.

Comment From: mhalbritter

There's a org.springframework.test.context.aot.TestRuntimeHintsRegistrar interface which can be hooked into, which generates runtime hints for tests. Going to use this.

Comment From: wilkinsona

I don't think we need to use hints for this. Instead, I think it will work if we change getOutputCapture to the following:

private OutputCapture getOutputCapture(ExtensionContext context) {
    return getStore(context).getOrComputeIfAbsent(OutputCapture.class, (key) -> new OutputCapture(), OutputCapture.class);
}

Comment From: mhalbritter

Ah, saw your comment too late. You're right, let's eliminate reflection altogether.