junit-team / junit5

✅ The 5th major version of the programmer-friendly testing framework for Java and the JVM

Home Page:https://junit.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Ability to inject extensions via Launcher to simplify testing

mauricioaniche opened this issue · comments

I'm writing a pretty complex JUnit plugin and writing lots of unit tests for it. Up to now, my plugin was a test listener. I was then able to test the listener by creating multiple "example unit tests" and running my listener on them, one-by-one, via the Launcher API.

Imagine that, in package fixture1 I have a test suite where all tests are green, and in package fixture2 I have a test suite where some tests are red. I then run these tests with my listener enabled, and I perform assertions.

Below the utility method I use to test the plugin against a specific fixture.

    protected void runTest(DiscoverySelector selector) {

        Launcher launcher = LauncherFactory.create();
        launcher.registerTestExecutionListeners(getExtension());

        LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
                .selectors(selector)
                .configurationParameter("junit.jupiter.extensions.autodetection.enabled", "false")
                .build();
        launcher.execute(request);
    }

The getExtension() method allows me to instantiate the listener in the way I want. This is especially important because then I can pass some mocks to its constructor. My plugins make API calls in case specific things happen, and that's why the need for mocks.

Now, I also need the plugin to implement TestExecutionExceptionHandler. However, there's no way for me to configure this handler via the Launcher. I can't use RegisterExtension or autodetection because I have to inject the mock.

Is there any way to inject an extension I'm missing here?

Thanks!

I think you can use RegisterExtension. The annotation works on static fields and IIR they do not have to be final, just not null when Jupiter attempts to register the extension. So you can assign to the field prior to running your test.

Though bear in mind that unless you use a singleton, in most circumstances your test listeners and jupiter extension will be different instances.

There's currently no way to pass an object via the launcher to an engine.

@mauricioaniche Does @mpkorstanje's idea work in your case?

Hi, @mpkorstanje, thanks for your comment! The idea of using RegisterExtension doesn't look that elegant to me, because the registration should happen in the test that serves as a fixture for my test, not on the test of the listener itself. I think it'd be easier to understand what I'm saying if I show up some code. I'll try to come up with a small example later!

@marcphilipp I managed to inject the mocked dependencies through some static trickery, so, in this sense, I managed to test what I wanted. I'll also add that to the small example, so you can see it. I was just curious for the reason why we can registerTestExecutionListeners via Launcher, but we can't register extensions.

I was just curious for the reason why we can registerTestExecutionListeners via Launcher, but we can't register extensions.

It is a consequence of the design of JUnit 5.

The Launcher is part of the JUnit Platform which provides a TestEngine abstraction that is implemented by JUnit Jupiter.

As extensions are a concept specific to the JUnit Jupiter test engine they can't be known by the launcher. Listeners in the other hand are part of the platform.

I think it'd be easier to understand what I'm saying if I show up some code. I'll try to come up with a small example later!

That might help.

By the way, what is the reason for using the TestExecutionExceptionHandler in combination with a test execution listener? They serve rather different purposes.

@mpkorstanje Thanks for the explanation!

I'm not combining them, no! I have implemented a bunch of listeners before and I was always able to test in the way I described above. But I just had to implement a TestExecutionExceptionHandler and when it came to testing, I noticed I couldn't inject mocks to the handler that easily.

Will get back with code soon!

If you would like us to be able to process this issue, please provide the requested information. If the information is not provided within the next 3 weeks, we will be unable to proceed and this issue will be closed.

Closing due to lack of requested feedback. If you would like to proceed with your contribution, please provide the requested information and we will re-open this issue.