How can I test a service provider implementation module with Junit 5?
Asked Answered
M

3

1

This is my base module which needs implementations of interfaces defined in myspi package. Various providers can offer MyProvider implementations. Base module uses them via myspi.MyProvider interface implementation.

module base {
    exports myspi;
    uses myspi.MyProvider;
}

This is my sample implementation module which provides the MyProvider implementation with MyProviderImpl

module myspi.provider {
    provides myspi.MyProvider with myspi.provider.MyProviderImpl;
}

All these work fine when I load the implementations in base module, with

public static List<MyProvider> getMyProviders() {
        var myProviders = new ArrayList<MyProvider>();
        for (MyProvider myProvider : ServiceLoader.<MyProvider>load(MyProvider.class)) {
            myProviders.add(myProvider);
        }
        return myProviders;
    }

But same code returns empty list in Junit 5 test code (ServiceLoader returns null). How can I test the service provider modules with Junit 5. Or is there any alternative to Junit that allows us to create test modules (modularized test API) that declares "uses myspi.MyProvider" in the module-info and works fine with getMyProviders()?

Mercurio answered 4/9, 2018 at 9:10 Comment(4)
This is worth a look #52110523 , the answer by Sormuras suggests how the world of testing with modules looks like.Softcover
I can already write black-box tests for other modules and access their exported packages. Here the problem is writing tests for service provider exports as I described above. I cannot load the service in tests. Any how, I'm now reading Sormuras' answer, hopping to find a clue. Maybe I should move the implementation as a plain old JAR without module-info, and test this jar as a simple lib, and use this lib to build the service provider module. But this is an ugly solution.Mercurio
Why don’t you just instantiate the provider with new MyProviderImpl()? Do you want to test the implementation or the configuration?Kamerman
johanneslink Because, there will be more than one MyProviderImpl(). They can offer different data content using the same API and the application will allow to switch between 3rd party providers. Sure I can test my single mock implementation but I've already done these test before Java 9. After modularization I want to test that my base module will find any 3rd party provider, and bind them to my app via base module utility classes so I can use all of them to test the rest of the base module API's. So in fact I want to test the rest of the base module with the content obtained from providers.Mercurio
M
1

SOLVED!

I've removed the Junit from class-path to module-path and also removed all Junit 4 compatibility stuff such as RunWith() etc, and made my test pure Junit 5 test.

I've added a module-info.java (Junit 5 doesn't require an open module although the books tell the opposite)

After I've modularized the tests I found that it still doesn't execute the ServiceLoader stuff. Then I've started looking for the fault myself.

And I found it! Running the ServiceLoader stuff in base module was possible, because the base module refers to the exported myProvider.jar, which in turns access a myProvider-config.properties file in the same directory. Without this config file myProvider cannot work properly.

The problematic test module on the other hand, refered the eclipse project of the myProvider instead of its exported .jar file and hence could not find its config file and exits. I'd moved this config file from Netbeans to Eclipse simply copying it into the same directory. Thus missing config file was the problem.

Changing the project settings I could run the tests without any failure.

I would like to thank all the contributors who responded.

Mercurio answered 5/9, 2018 at 7:1 Comment(1)
Glad you sorted it out! I wrote about "Testing In The Modular World" here: sormuras.github.io/blog/2018-09-11-testing-in-the-modular-worldSecondclass
S
1

Basically you're on the right track. You need to convince the Java module system that your test modules are the single source of thruth when it comes to resolve modules are test runtime.

Black-box testing is easy.

White-box testing in the modular world, meaning testing protected and package private members within a module, is tricky. There are at least two ways to achieve this: a) use java command line options to configure the Java module system at test startup or b) blend main sources into the test sources at compile time and maintain a dedicated module-info.java in your test sources.

Please visit the links to the blogs and examples posted over at How to make a modular build with jdk > 1.8 Here is an excerpt for convenience:

Examples

Background and other resources

And expect most IDE to not support you either. For now.

Secondclass answered 4/9, 2018 at 14:14 Comment(1)
Thank you, Sormuras. I've already accessed and read your reference links through the nullpointer's comment above. Tonight I'll try to open test module as shown in one of your links and in the book "Java 9 Modularity, Sander Mak & Paul Bakker ". In this context I'd wish that you could give me a shorter answer, to run the getMyProviders() method above. I need it to be able to test rest of the packages in my base module. I do not write any WhiteBox test, because they are fragile.Mercurio
M
1

SOLVED!

I've removed the Junit from class-path to module-path and also removed all Junit 4 compatibility stuff such as RunWith() etc, and made my test pure Junit 5 test.

I've added a module-info.java (Junit 5 doesn't require an open module although the books tell the opposite)

After I've modularized the tests I found that it still doesn't execute the ServiceLoader stuff. Then I've started looking for the fault myself.

And I found it! Running the ServiceLoader stuff in base module was possible, because the base module refers to the exported myProvider.jar, which in turns access a myProvider-config.properties file in the same directory. Without this config file myProvider cannot work properly.

The problematic test module on the other hand, refered the eclipse project of the myProvider instead of its exported .jar file and hence could not find its config file and exits. I'd moved this config file from Netbeans to Eclipse simply copying it into the same directory. Thus missing config file was the problem.

Changing the project settings I could run the tests without any failure.

I would like to thank all the contributors who responded.

Mercurio answered 5/9, 2018 at 7:1 Comment(1)
Glad you sorted it out! I wrote about "Testing In The Modular World" here: sormuras.github.io/blog/2018-09-11-testing-in-the-modular-worldSecondclass
R
-1

This is quite an old post but if anyone gets here trying to test java modules with junit 5 with gradle, especially the consumer/provider as presented in this post , Sormuras solution is the easy way, to patch the consumer module with the tests classes. it is supported by gradle-modules-plugin that does that out of the box: https://github.com/java9-modularity/gradle-modules-plugin

Rumsey answered 29/12, 2021 at 0:3 Comment(1)
A link to a solution is welcome, but please ensure your answer is useful without it: add context around the link so your fellow users will have some idea what it is and why it is there, then quote the most relevant part of the page you are linking to in case the target page is unavailable. Answers that are little more than a link may be deleted.Crumpler

© 2022 - 2024 — McMap. All rights reserved.