Hi Marc, With forkCount = 1 it works fine, the problem is with forkCount > 1. The Arquillian extension registers its state in the store at the root of the TestPlan. When running with forkCount > 1, surefire sets up a load balancer in the main process. This load balancer streams tests one by one to the forks. The forks run a test, and request the next one when done. This is implemented by creating a LauncherDiscoveryRequest per test. This in turn results in a separate TestPlan per test, causing the state of Arquillian to be rebuilt over and over again. When running with forkCount = 1, only a single LauncherDiscoveryRequest is created and all tests are part of the same TestPlan.
The Arquillian extension can be modified to use a LauncherSessionListener, but this will require changes to the code base. The same is probably true for other extensions. Best regards, Emond On Mon, Sep 13, 2021 at 7:51 AM Marc Philipp <m...@gradle.com> wrote: > Hi Emond, > > could you please elaborate why the LauncherSessionListener approach > doesn’t work for forkCount=1 for Arquillian? > > Cheers, > > Marc > > On Sunday, Sep 12, 2021 at 9:37 PM, Emond Papegaaij < > emond.papega...@gmail.com> wrote: > Hi Marc, > > Thanks for the links to the documentation. This really helps for my > Arquillian-Spock extension. It's good to know the LauncherSession was > introduced to solve this issue. > > The problem I see with this new API is that it requires the extension to > explicitly make use of it. For example, the JUnit 5 Arquillian extension > will need to be adapted to this new API to work correctly with a forkCount > > 1. The same will probably hold for other extensions. The cause of this is > > that separate invocations of the launcher do not really share a life > cycle. > LauncherSession is able to bind these invocations together, but the engine > will be run over and over again. JUnit does support streaming tests in a > lazy way via the DynamicTest API. It would be great if this could somehow > be exposed via the LauncherDiscoveryRequest. That would IMHO really solve > this issue. > > Best regards, > Emond > > On Sat, Sep 11, 2021 at 7:52 AM Marc Philipp <m...@gradle.com> wrote: > > Hi Emond and Tibor, > > I’m glad you discovered the new LauncherSession API which was added for > this purpose. The JUnit 5.8 GA release will come in the next few days. > > As you mentrioned, the official documentation does not (yet!) do a good > job of explaining its intended use case: > > > https://junit.org/junit5/docs/5.8.0-RC1/user-guide/#launcher-api-launcher-session-listeners-custom > > Here’s a more complete example that I wrote for Gradle’s test distribution > plugin: > > > https://docs.gradle.com/enterprise/test-distribution-gradle-plugin/#junit_5_8_and_later > > It demonstrates how to initialize a “fixture” only once for an entire > session and only if tests are actually going to be executed not just > discovered. I’ll make sure to update the official JUnit docs to include a > similar example before the release. > > To only differentiate between the different versions of JUnit in one place > and stay backwards compatible, you could create an adapter class like > this: > > public class BackwardsCompatibleLauncherSession implements AutoCloseable { > > public static BackwardsCompatibleLauncherSession open() { > try { > LauncherSession launcherSession = > LauncherFactory.openSession(); > return new > BackwardsCompatibleLauncherSession(launcherSession.getLauncher(), > launcherSession::close); > } catch (NoSuchMethodError ignore) { > // JUnit Platform version on test classpath does not yet > support launcher sessions > return new > BackwardsCompatibleLauncherSession(LauncherFactory.create(), () -> {}); > } > } > > private final Launcher launcher; > private final Runnable onClose; > > private BackwardsCompatibleLauncherSession(Launcher launcher, Runnable > onClose) { > this.launcher = launcher; > this.onClose = onClose; > } > > Launcher getLauncher() { > return launcher; > } > > @Override > public void close() { > onClose.run(); > } > } > > Cheers, > > Marc > >